From: Alessio Treglia
Date: Wed, 16 Jan 2013 16:08:33 +0000 (+0000)
Subject: Imported Upstream version 0.5.0+svn4281~dfsg1
X-Git-Tag: archive/raspbian/1.0.1+dfsg1-4+rpi1~1^2~15^2~13
X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=32aaace1f109f466b90258ed3598394edb6d302c;p=gpac.git
Imported Upstream version 0.5.0+svn4281~dfsg1
---
diff --git a/README b/README
index ab1c8cd..ccb6ea6 100644
--- a/README
+++ b/README
@@ -7,7 +7,7 @@ mozilla SpiderMonkey javascript engine.
GPAC currently supports local playback, http progressive download, Adaptive HTTP Streaming (MPEG-DASH, HLS), RTP/RTSP streaming over UDP (unicast or multicast) or TCP and TS demuxing (from file, IP or DVB4Linux).
GPAC also features MP4Box, a multimedia swiss-army knife for the prompt.
-For compilation and installation instruction, check INSTALL file
+For compilation and installation instruction, check INSTALLME file
For GPAC configuration instruction, check gpac/doc/configuration.html or gpac/doc/man/gpac.1 (man gpac when installed)
diff --git a/applications/mp42ts/main.c b/applications/mp42ts/main.c
index 0eedc25..ee6f3cd 100644
--- a/applications/mp42ts/main.c
+++ b/applications/mp42ts/main.c
@@ -36,6 +36,8 @@
#include
#endif
+#define USE_ISOBMF_REWRITE
+
#ifdef GPAC_DISABLE_ISOM
@@ -137,13 +139,16 @@ typedef struct
u32 image_repeat_ms, nb_repeat_last;
void *dsi;
u32 dsi_size;
- u32 nalu_size;
+
void *dsi_and_rap;
Bool loop;
Bool is_repeat;
u64 ts_offset;
M2TSProgram *prog;
- char nalu_delim[6];
+
+#ifndef USE_ISOBMF_REWRITE
+ u32 nalu_size;
+#endif
} GF_ESIMP4;
typedef struct
@@ -215,6 +220,7 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param)
pck.flags |= GF_ESI_DATA_HAS_DTS;
}
+#ifndef USE_ISOBMF_REWRITE
if (priv->nalu_size) {
Bool nalu_delim_sent = 0;
u32 remain = priv->sample->dataLength;
@@ -271,7 +277,10 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param)
ptr += size;
}
- } else {
+ } else
+#endif //USE_ISOBMF_REWRITE
+
+ {
if (priv->sample->IsRAP && priv->dsi && priv->dsi_size) {
pck.data = priv->dsi;
@@ -375,14 +384,21 @@ static void fill_isom_es_ifce(M2TSProgram *prog, GF_ESInterface *ifce, GF_ISOFil
priv->dsi_size = dcd->decoderSpecificInfo->dataLength;
memcpy(priv->dsi, dcd->decoderSpecificInfo->data, dcd->decoderSpecificInfo->dataLength);
break;
+ case GPAC_OTI_VIDEO_HEVC:
+ gf_isom_set_nalu_extract_mode(mp4, track_num, GF_ISOM_NALU_EXTRACT_LAYER_ONLY | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG | GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG);
+ break;
case GPAC_OTI_VIDEO_AVC:
{
-#ifndef GPAC_DISABLE_AV_PARSERS
+#ifdef USE_ISOBMF_REWRITE
+ gf_isom_set_nalu_extract_mode(mp4, track_num, GF_ISOM_NALU_EXTRACT_LAYER_ONLY | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG | GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG);
+
+#elif !defined(GPAC_DISABLE_AV_PARSERS)
GF_AVCConfigSlot *slc;
u32 i;
GF_BitStream *bs;
GF_AVCConfig *avccfg = gf_isom_avc_config_get(mp4, track_num, 1);
priv->nalu_size = avccfg->nal_unit_size;
+
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
for (i=0; isequenceParameterSets);i++) {
slc = gf_list_get(avccfg->sequenceParameterSets, i);
@@ -398,9 +414,7 @@ static void fill_isom_es_ifce(M2TSProgram *prog, GF_ESInterface *ifce, GF_ISOFil
gf_bs_del(bs);
gf_odf_avc_cfg_del(avccfg);
#endif
- priv->nalu_delim[3] = 1;
- priv->nalu_delim[4] = 0; /*this will be nal header*/
- priv->nalu_delim[5] = 0xF0 /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/;
+
}
break;
}
diff --git a/applications/mp4box/filedump.c b/applications/mp4box/filedump.c
index 147426e..285deca 100644
--- a/applications/mp4box/filedump.c
+++ b/applications/mp4box/filedump.c
@@ -873,13 +873,51 @@ void dump_file_timestamps(GF_ISOFile *file, char *inName)
}
-static void dump_nalu_type_name(FILE *dump, char *ptr, Bool is_svc)
+static void dump_nalu(FILE *dump, char *ptr, Bool is_svc, Bool is_hevc)
{
- u8 type = ptr[0] & 0x1F;
+ u8 type;
u8 dependency_id, quality_id, temporal_id;
u8 track_ref_index;
- u32 data_offset;
+ u32 data_offset, sps_id, pps_id;
+ if (is_hevc) {
+ type = (ptr[0] & 0x7E) >> 1;
+ fprintf(dump, "code=\"%d\" type=\"", type);
+ switch (type) {
+ case GF_HEVC_NALU_SLICE_TRAIL_N: fputs("TRAIL_N slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_TRAIL_R: fputs("TRAIL_R slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_TSA_N: fputs("TSA_N slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_TSA_R: fputs("TSA_R slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_STSA_N: fputs("STSA_N slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_STSA_R: fputs("STSA_R slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_RADL_N: fputs("RADL_N slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_RADL_R: fputs("RADL_R slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_RASL_N: fputs("RASL_N slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_RASL_R: fputs("RASL_R slice segment", dump); break;
+ case GF_HEVC_NALU_SLICE_BLA_W_LP: fputs("Broken link access slice (W LP)", dump); break;
+ case GF_HEVC_NALU_SLICE_BLA_W_DLP: fputs("Broken link access slice (W DLP)", dump); break;
+ case GF_HEVC_NALU_SLICE_BLA_N_LP: fputs("Broken link access slice (N LP)", dump); break;
+ case GF_HEVC_NALU_SLICE_IDR_W_DLP: fputs("IDR slice (W DLP)", dump); break;
+ case GF_HEVC_NALU_SLICE_IDR_N_LP: fputs("IDR slice (N LP)", dump); break;
+ case GF_HEVC_NALU_SLICE_CRA: fputs("CRA slice", dump); break;
+
+ case GF_HEVC_NALU_VID_PARAM: fputs("Video Parameter Set", dump); break;
+ case GF_HEVC_NALU_SEQ_PARAM: fputs("Sequence Parameter Set", dump); break;
+ case GF_HEVC_NALU_PIC_PARAM: fputs("Picture Parameter Set", dump); break;
+ case GF_HEVC_NALU_ACCESS_UNIT: fputs("AU Delimiter", dump); break;
+ case GF_HEVC_NALU_END_OF_SEQ: fputs("End of Sequence", dump); break;
+ case GF_HEVC_NALU_END_OF_STREAM: fputs("End of Stream", dump); break;
+ case GF_HEVC_NALU_FILLER_DATA: fputs("Filler Data", dump); break;
+ case GF_HEVC_NALU_SEI_PREFIX: fputs("SEI Prefix", dump); break;
+ case GF_HEVC_NALU_SEI_SUFFIX: fputs("SEI Suffix", dump); break;
+ default:
+ fputs("UNKNOWN", dump); break;
+ }
+ fputs("\"", dump);
+ return;
+ }
+
+ type = ptr[0] & 0x1F;
fprintf(dump, "code=\"%d\" type=\"", type);
switch (type) {
case GF_AVC_NALU_NON_IDR_SLICE: fputs("Non IDR slice", dump); break;
@@ -888,15 +926,27 @@ static void dump_nalu_type_name(FILE *dump, char *ptr, Bool is_svc)
case GF_AVC_NALU_DP_C_SLICE: fputs("DP Type C slice", dump); break;
case GF_AVC_NALU_IDR_SLICE: fputs("IDR slice", dump); break;
case GF_AVC_NALU_SEI: fputs("SEI Message", dump); break;
- case GF_AVC_NALU_SEQ_PARAM: fputs("SequenceParameterSet", dump); break;
- case GF_AVC_NALU_PIC_PARAM: fputs("PictureParameterSet", dump); break;
+ case GF_AVC_NALU_SEQ_PARAM:
+ fputs("SequenceParameterSet", dump);
+ gf_avc_get_sps_info(ptr, strlen(ptr), &sps_id, NULL, NULL, NULL, NULL);
+ fprintf(dump, "\" sps_id=\"%d", sps_id);
+ break;
+ case GF_AVC_NALU_PIC_PARAM:
+ fputs("PictureParameterSet", dump);
+ gf_avc_get_pps_info(ptr+1, strlen(ptr)-1, &pps_id, &sps_id);
+ fprintf(dump, "\" pps_id=\"%d\" sps_id=\"%d", pps_id, sps_id);
+ break;
case GF_AVC_NALU_ACCESS_UNIT: fputs("AccessUnit delimiter", dump); break;
case GF_AVC_NALU_END_OF_SEQ: fputs("EndOfSequence", dump); break;
case GF_AVC_NALU_END_OF_STREAM: fputs("EndOfStream", dump); break;
case GF_AVC_NALU_FILLER_DATA: fputs("Filler data", dump); break;
case GF_AVC_NALU_SEQ_PARAM_EXT: fputs("SequenceParameterSetExtension", dump); break;
case GF_AVC_NALU_SVC_PREFIX_NALU: fputs("SVCPrefix", dump); break;
- case GF_AVC_NALU_SVC_SUBSEQ_PARAM: fputs("SVCSubsequenceParameterSet", dump); break;
+ case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
+ fputs("SVCSubsequenceParameterSet", dump);
+ gf_avc_get_sps_info(ptr, strlen(ptr), &sps_id, NULL, NULL, NULL, NULL);
+ fprintf(dump, "\" sps_id=\"%d", sps_id);
+ break;
case GF_AVC_NALU_SLICE_AUX: fputs("Auxiliary Slice", dump); break;
case GF_AVC_NALU_SVC_SLICE:
@@ -922,10 +972,13 @@ static void dump_nalu_type_name(FILE *dump, char *ptr, Bool is_svc)
void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
{
- u32 i, count, track, nalh_size;
+ u32 i, count, track, nalh_size, timescale, cur_extract_mode;
+ Bool is_hevc = 0;
FILE *dump;
+ s32 countRef;
#ifndef GPAC_DISABLE_AV_PARSERS
GF_AVCConfig *avccfg, *svccfg;
+ GF_HEVCConfig *hevccfg;
GF_AVCConfigSlot *slc;
#endif
@@ -941,20 +994,25 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
count = gf_isom_get_sample_count(file, track);
- fprintf(dump, "\n", trackID, count);
+ timescale = gf_isom_get_media_timescale(file, track);
+
+ cur_extract_mode = gf_isom_get_nalu_extract_mode(file, track);
+
+ fprintf(dump, "\n", trackID, count, timescale);
#ifndef GPAC_DISABLE_AV_PARSERS
avccfg = gf_isom_avc_config_get(file, track, 1);
svccfg = gf_isom_svc_config_get(file, track, 1);
+ hevccfg = gf_isom_hevc_config_get(file, track, 1);
fprintf(dump, " \n");
#define DUMP_ARRAY(arr, name)\
if (arr) {\
for (i=0; idata , svccfg ? 1 : 0);\
- fprintf(dump, ">\n");\
+ fprintf(dump, " <%s number=\"%d\" size=\"%d\"", name, i+1, slc->size);\
+ dump_nalu(dump, slc->data , svccfg ? 1 : 0, is_hevc);\
+ fprintf(dump, "/>\n");\
}\
}\
@@ -972,10 +1030,42 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
DUMP_ARRAY(svccfg->sequenceParameterSets, "SVCSPSArray")
DUMP_ARRAY(svccfg->pictureParameterSets, "SVCPPSArray")
}
+ if (hevccfg) {
+ nalh_size = hevccfg->nal_unit_size;
+ is_hevc = 1;
+ for (i=0; iparam_array); i++) {
+ GF_HEVCParamArray *ar = gf_list_get(hevccfg->param_array, i);
+ if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
+ DUMP_ARRAY(ar->nalus, "HEVCSPSArray")
+ } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) {
+ DUMP_ARRAY(ar->nalus, "HEVCPPSArray")
+ } else if (ar->type==GF_HEVC_NALU_VID_PARAM) {
+ DUMP_ARRAY(ar->nalus, "HEVCVPSArray")
+ } else {
+ DUMP_ARRAY(ar->nalus, "HEVCUnknownPSArray")
+ }
+ }
+ }
#endif
fprintf(dump, " \n");
+ /*for testing dependency*/
+ countRef = gf_isom_get_reference_count(file, track, GF_ISOM_REF_SCAL);
+ if (countRef > 0)
+ {
+ u32 refTrackID;
+ fprintf(dump, " \n");
+ for (i = 1; i <= (u32) countRef; i++)
+ {
+ gf_isom_get_reference_ID(file, track, GF_ISOM_REF_SCAL, i, &refTrackID);
+ fprintf(dump, " \n", i, refTrackID);
+ }
+
+ fprintf(dump, " \n");
+ }
+
fprintf(dump, " \n");
+ gf_isom_set_nalu_extract_mode(file, track, GF_ISOM_NALU_EXTRACT_INSPECT);
for (i=0; i\n");
}
idx++;
@@ -1021,6 +1111,9 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
fprintf(dump, "\n");
if (inName) fclose(dump);
+ if (avccfg) gf_odf_avc_cfg_del(avccfg);
+ if (svccfg) gf_odf_avc_cfg_del(svccfg);
+ gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode);
}
#ifndef GPAC_DISABLE_ISOM_DUMP
@@ -1300,8 +1393,12 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
|| (msub_type==GF_ISOM_SUBTYPE_MPEG4_CRYP)
|| (msub_type==GF_ISOM_SUBTYPE_AVC_H264)
|| (msub_type==GF_ISOM_SUBTYPE_AVC2_H264)
+ || (msub_type==GF_ISOM_SUBTYPE_AVC3_H264)
+ || (msub_type==GF_ISOM_SUBTYPE_AVC4_H264)
|| (msub_type==GF_ISOM_SUBTYPE_SVC_H264)
|| (msub_type==GF_ISOM_SUBTYPE_LSR1)
+ || (msub_type==GF_ISOM_SUBTYPE_HVC1)
+ || (msub_type==GF_ISOM_SUBTYPE_HEV1)
) {
esd = gf_isom_get_esd(file, trackNum, 1);
if (!esd) {
@@ -1369,7 +1466,7 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
}
}
if (avccfg->chroma_bit_depth) {
- fprintf(stderr, "\tChroma format %d - Luma bit depth %d - chroma bot depth %d\n", avccfg->chroma_format, avccfg->luma_bit_depth, avccfg->chroma_bit_depth);
+ fprintf(stderr, "\tChroma format %d - Luma bit depth %d - chroma bit depth %d\n", avccfg->chroma_format, avccfg->luma_bit_depth, avccfg->chroma_bit_depth);
}
gf_odf_avc_cfg_del(avccfg);
}
@@ -1392,7 +1489,42 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
gf_odf_avc_cfg_del(svccfg);
}
#endif /*GPAC_DISABLE_AV_PARSERS*/
+
+ } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_HEVC) {
+#ifndef GPAC_DISABLE_AV_PARSERS
+ GF_HEVCConfig *hevccfg;
+#endif
+
+ gf_isom_get_visual_info(file, trackNum, 1, &w, &h);
+ if (full_dump) fprintf(stderr, "\t");
+ fprintf(stderr, "HEVC Video - Visual Size %d x %d\n", w, h);
+#ifndef GPAC_DISABLE_AV_PARSERS
+ hevccfg = gf_isom_hevc_config_get(file, trackNum, 1);
+ if (!hevccfg ) {
+ fprintf(stderr, "\n\n\tNon-compliant HEVC track: hvcC not found in sample description\n");
+ } else {
+ u32 k;
+ fprintf(stderr, "\tHEVC Info: Profile IDC %d - Level IDC %d - Chroma Format %d\n", hevccfg->profile_idc, hevccfg->level_idc, hevccfg->chromaFormat);
+ fprintf(stderr, "\tNAL Unit length bits: %d - profile compatibility 0x%08X\n", 8*hevccfg->nal_unit_size, hevccfg->profile_compatibility_indications);
+ fprintf(stderr, "\tParameter Sets: ");
+ for (k=0; kparam_array); k++) {
+ GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k);
+ if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
+ fprintf(stderr, "%d SPS ", gf_list_count(ar->nalus));
+ }
+ else if (ar->type==GF_HEVC_NALU_PIC_PARAM) {
+ fprintf(stderr, "%d PPS ", gf_list_count(ar->nalus));
+ }
+ if (ar->type==GF_HEVC_NALU_VID_PARAM) {
+ fprintf(stderr, "%d VPS ", gf_list_count(ar->nalus));
+ }
+ }
+ fprintf(stderr, "\n\tBit Depth luma %d - Chroma %d - %d temporal layers\n", hevccfg->luma_bit_depth, hevccfg->chroma_bit_depth, hevccfg->numTemporalLayers);
+ gf_odf_hevc_cfg_del(hevccfg);
+ }
+#endif /*GPAC_DISABLE_AV_PARSERS*/
}
+
/*OGG media*/
else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_MEDIA_OGG) {
char *szName;
@@ -1444,7 +1576,8 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
if (full_dump) fprintf(stderr, "\t");
if (e) fprintf(stderr, "Corrupted AAC Config\n");
else {
- fprintf(stderr, "MPEG-%d Audio %s - %d Channel(s) - SampleRate %d", is_mp2 ? 2 : 4, gf_m4a_object_type_name(a_cfg.base_object_type), a_cfg.nb_chan, a_cfg.base_sr);
+ fprintf(stderr, "%s - %d Channel(s) - SampleRate %d", gf_m4a_object_type_name(a_cfg.base_object_type), a_cfg.nb_chan, a_cfg.base_sr);
+ if (is_mp2) fprintf(stderr, " (MPEG-2 Signaling)");
if (a_cfg.has_sbr) fprintf(stderr, " - SBR SampleRate %d", a_cfg.sbr_sr);
if (a_cfg.has_ps) fprintf(stderr, " - PS");
fprintf(stderr, "\n");
@@ -1946,7 +2079,7 @@ void DumpMovieInfo(GF_ISOFile *file)
fprintf(stderr, "\tTempo (BPM): %d\n", tag[1]);
}
}
- if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_TRACKNUMBER, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tTrackNumber: %d / %d\n", tag[3], tag[5]);
+ if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_TRACKNUMBER, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tTrackNumber: %d / %d\n", (0xff00 & (tag[2]<<8)) | (0xff & tag[3]), (0xff00 & (tag[4]<<8)) | (0xff & tag[5]));
if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_TRACK, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tTrack: %s\n", tag);
if (gf_isom_apple_get_tag(file, GF_ISOM_ITUNE_GROUP, &tag, &tag_len)==GF_OK) fprintf(stderr, "\tGroup: %s\n", tag);
diff --git a/applications/mp4box/fileimport.c b/applications/mp4box/fileimport.c
index e1976a8..d364d37 100644
--- a/applications/mp4box/fileimport.c
+++ b/applications/mp4box/fileimport.c
@@ -41,6 +41,7 @@
#ifndef GPAC_DISABLE_VRML
#include
#endif
+#include
#ifndef GPAC_DISABLE_ISOM_WRITE
@@ -155,6 +156,27 @@ void convert_file_info(char *inName, u32 trackID)
if (!found && trackID) fprintf(stderr, "Cannot find track %d in file\n", trackID);
}
+static void set_chapter_track(GF_ISOFile *file, u32 track, u32 chapter_ref_trak)
+{
+ u64 ref_duration, chap_duration;
+ Double scale;
+
+ gf_isom_set_track_reference(file, chapter_ref_trak, GF_4CC('c','h','a','p'), gf_isom_get_track_id(file, track) );
+ gf_isom_set_track_enabled(file, track, 0);
+
+ ref_duration = gf_isom_get_media_duration(file, chapter_ref_trak);
+ chap_duration = gf_isom_get_media_duration(file, track);
+ scale = (Double) (s64) gf_isom_get_media_timescale(file, track);
+ scale /= gf_isom_get_media_timescale(file, chapter_ref_trak);
+ ref_duration = (u64) (ref_duration * scale);
+
+ if (chap_duration < ref_duration) {
+ chap_duration -= gf_isom_get_sample_duration(file, track, gf_isom_get_sample_count(file, track));
+ chap_duration = ref_duration - chap_duration;
+ gf_isom_set_last_sample_duration(file, track, (u32) chap_duration);
+ }
+}
+
GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample)
{
u32 track_id, i, timescale, track, stype, profile, level, new_timescale, rescale, svc_mode;
@@ -425,7 +447,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc
import.video_fps = force_fps;
import.frames_per_sample = frames_per_sample;
import.flags = import_flags;
-
+
if (!import.nb_tracks) {
u32 count, o_count;
o_count = gf_isom_get_track_count(import.dest);
@@ -458,13 +480,12 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc
if (handler_name) gf_isom_set_handler_name(import.dest, i+1, handler_name);
else if (!keep_handler) {
char szHName[1024];
- char *fName = strrchr(inName, '/');
- if (!fName) fName = strrchr(inName, '\\');
+ const char *fName = gf_url_get_resource_name((const char *)inName);
+ fName = strchr(fName, '.');
+ if (fName) fName += 1;
+ else fName = "?";
- if (!fName) fName = inName;
- else fName = fName+1;
-
- sprintf(szHName, "%s - Imported with GPAC %s", fName, GPAC_FULL_VERSION);
+ sprintf(szHName, "*%s@GPAC%s", fName, GPAC_FULL_VERSION);
gf_isom_set_handler_name(import.dest, i+1, szHName);
}
if (handler) gf_isom_set_media_type(import.dest, i+1, handler);
@@ -480,8 +501,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc
gf_isom_set_media_subtype(import.dest, i+1, 1, stype);
if (is_chap && chap_ref) {
- gf_isom_set_track_reference(import.dest, chap_ref, GF_4CC('c','h','a','p'), gf_isom_get_track_id(import.dest, i+1) );
- gf_isom_set_track_enabled(import.dest, i+1, 0);
+ set_chapter_track(import.dest, i+1, chap_ref);
}
if (profile || level)
@@ -492,8 +512,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc
gf_isom_set_composition_offset_mode(import.dest, i+1, negative_cts_offset);
- /*when importing SVC we ALWAYS have AVC+SVC single track mode*/
- if (gf_isom_get_avc_svc_type(import.dest, i+1, 1)==GF_ISOM_AVCTYPE_AVC_SVC)
+ if (gf_isom_get_avc_svc_type(import.dest, i+1, 1)>=GF_ISOM_AVCTYPE_AVC_SVC)
check_track_for_svc = i+1;
}
} else {
@@ -547,13 +566,12 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc
if (handler_name) gf_isom_set_handler_name(import.dest, track, handler_name);
else if (!keep_handler) {
char szHName[1024];
- char *fName = strrchr(inName, '/');
- if (!fName) fName = strrchr(inName, '\\');
-
- if (!fName) fName = inName;
- else fName = fName+1;
+ const char *fName = gf_url_get_resource_name((const char *)inName);
+ fName = strchr(fName, '.');
+ if (fName) fName += 1;
+ else fName = "?";
- sprintf(szHName, "%s - Imported with GPAC %s", fName, GPAC_FULL_VERSION);
+ sprintf(szHName, "%s@GPAC%s", fName, GPAC_FULL_VERSION);
gf_isom_set_handler_name(import.dest, track, szHName);
}
if (handler) gf_isom_set_media_type(import.dest, track, handler);
@@ -569,8 +587,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc
gf_isom_set_media_subtype(import.dest, track, 1, stype);
if (is_chap && chap_ref) {
- gf_isom_set_track_reference(import.dest, chap_ref, GF_4CC('c','h','a','p'), gf_isom_get_track_id(import.dest, i+1) );
- gf_isom_set_track_enabled(import.dest, track, 0);
+ set_chapter_track(import.dest, track, chap_ref);
}
if (profile || level)
@@ -618,8 +635,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc
gf_isom_set_composition_offset_mode(import.dest, track, negative_cts_offset);
- /*when importing SVC we ALWAYS have AVC+SVC single track mode*/
- if (gf_isom_get_avc_svc_type(import.dest, track, 1)==GF_ISOM_AVCTYPE_AVC_SVC)
+ if (gf_isom_get_avc_svc_type(import.dest, track, 1)>=GF_ISOM_AVCTYPE_AVC_SVC)
check_track_for_svc = track;
}
if (track_id) fprintf(stderr, "WARNING: Track ID %d not found in file\n", track_id);
@@ -635,6 +651,16 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc
}
}
+ /*force to rewrite all dependencies*/
+ for (i = 1; i <= gf_isom_get_track_count(import.dest); i++)
+ {
+ e = gf_isom_rewrite_track_dependencies(import.dest, i);
+ if (e) {
+ fprintf(stderr, "Warning: track ID %d has references to a track not imported\n", gf_isom_get_track_id(import.dest, i));
+ e = GF_OK;
+ }
+ }
+
if (check_track_for_svc) {
if (svc_mode) {
e = gf_media_split_svc(import.dest, check_track_for_svc, (svc_mode==2) ? 1 : 0);
@@ -1359,8 +1385,10 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou
for (i=0; iDTS;
- samp->DTS = (u64) (ts_scale * samp->DTS + insert_dts);
+ samp->DTS = (u64) (ts_scale * samp->DTS + (new_track ? 0 : insert_dts));
samp->CTS_Offset = (u32) (samp->CTS_Offset * ts_scale);
if (gf_isom_is_self_contained(orig, i+1, di)) {
@@ -1607,7 +1651,18 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou
gf_isom_set_last_sample_duration(dest, dst_tk, (u32) insert_dts);
}
- if (merge_edits) {
+ if (new_track && insert_dts) {
+ u64 media_dur = gf_isom_get_media_duration(orig, i+1);
+ /*convert from media time to track time*/
+ Double rescale = (Float) gf_isom_get_timescale(dest);
+ rescale /= (Float) gf_isom_get_media_timescale(dest, dst_tk);
+ /*convert from orig to dst time scale*/
+ rescale *= ts_scale;
+
+ gf_isom_set_edit_segment(dest, dst_tk, 0, (u64) (s64) (insert_dts*rescale), 0, GF_ISOM_EDIT_EMPTY);
+ gf_isom_set_edit_segment(dest, dst_tk, (u64) (s64) (insert_dts*rescale), (u64) (s64) (media_dur*rescale), 0, GF_ISOM_EDIT_NORMAL);
+ }
+ else if (merge_edits) {
/*convert from media time to track time*/
Double rescale = (Float) gf_isom_get_timescale(dest);
rescale /= (Float) gf_isom_get_media_timescale(dest, dst_tk);
diff --git a/applications/mp4box/main.c b/applications/mp4box/main.c
index 2051753..3418979 100644
--- a/applications/mp4box/main.c
+++ b/applications/mp4box/main.c
@@ -213,6 +213,7 @@ void PrintGeneralUsage()
" * Note 1: some tracks may be removed in the process\n"
" * Note 2: always on for *.3gp *.3g2 *.3gpp\n"
" -ipod rewrites the file for iPod\n"
+ " -psp rewrites the file for PSP devices\n"
" -brand ABCD[:v] sets major brand of file, with optional version\n"
" -ab ABCD adds given brand to file's alternate brand list\n"
" -rb ABCD removes given brand from file's alternate brand list\n"
@@ -271,14 +272,21 @@ void PrintDASHUsage()
" Note: for onDemand profile, sets duration of a subsegment\n"
" -frag time_in_ms Specifies a fragment duration of time_in_ms.\n"
" * Note: By default, this is the DASH duration\n"
- " -out filename specifies output file name\n"
- " * Note: By default input (MP4,3GP) file is overwritten\n"
+ " -out filename specifies output MPD file name.\n"
" -tmp dirname specifies directory for temporary file creation\n"
" * Note: Default temp dir is OS-dependent\n"
" -profile NAME specifies the target DASH profile: \"onDemand\", \"live\", \"main\", \"simple\", \"full\"\n"
" * This will set default option values to ensure conformance to the desired profile\n"
" * Default profile is \"full\" in static mode, \"live\" in dynamic mode\n"
"\n"
+ "Input media files to dash can use the following modifiers\n"
+ " \":id=NAME\" sets the representation ID to NAME\n"
+ " \":period=NAME\" sets the representation's period to NAME. Multiple periods may be used\n"
+ " period appear in the MPD in the same order as specified with this option\n"
+ " \":bandwidth=VALUE\" sets the representation's bandwidth to a given value\n"
+ " \":role=VALUE\" sets the role of this representation (cf DASH spec).\n"
+ " media with different roles belong to different adaptation sets.\n"
+ "\n"
" -rap segments begin with random access points\n"
" Note: segment duration may not be exactly what asked by\n"
" \"-dash\" since encoded video data is not modified\n"
@@ -312,7 +320,7 @@ void PrintDASHUsage()
" -daisy-chain uses daisy-chain SIDX instead of hierarchical. Ignored if frags/sidx is 0.\n"
" -single-segment uses a single segment for the whole file (OnDemand profile). \n"
" -single-file uses a single file for the whole file (default). \n"
- " -bs-switching MODE sets bitstream switching to \"yes\" (default), \"no\" or \"single\" to test with single input.\n"
+ " -bs-switching MODE sets bitstream switching to \"yes\" (default), \"merge\", \"no\" or \"single\" to test with single input.\n"
" -dash-ts-prog N program_number to be considered in case of an MPTS input file.\n"
"\n");
}
@@ -563,6 +571,7 @@ void PrintExtractUsage()
" -saf remux file to SAF multiplex\n"
" -dvbhdemux demux DVB-H file into IP Datagrams\n"
" * Note: can be used when encoding scene descriptions\n"
+ " -raw-layer ID same as -raw but skips SVC/MVC extractors when extracting\n"
" -diod extracts file IOD in raw format when supported\n"
"\n");
}
@@ -1292,6 +1301,7 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char *
if (!strnicmp(opts, "id=", 3)) strncpy(di->representationID, opts+3, 99);
else if (!strnicmp(opts, "period=", 7)) strncpy(di->periodID, opts+7, 99);
else if (!strnicmp(opts, "bandwidth=", 10)) di->bandwidth = atoi(opts+10);
+ else if (!strnicmp(opts, "role=", 5)) strncpy(di->role, opts+5, 99);
if (!sep) break;
sep[0] = ':';
@@ -1321,9 +1331,10 @@ int mp4boxMain(int argc, char **argv)
s32 subsegs_per_sidx;
u32 *brand_add = NULL;
u32 *brand_rem = NULL;
- u32 i, stat_level, hint_flags, info_track_id, import_flags, nb_add, nb_cat, ismaCrypt, agg_samples, nb_sdp_ex, max_ptime, raw_sample_num, split_size, nb_meta_act, nb_track_act, rtp_rate, major_brand, nb_alt_brand_add, nb_alt_brand_rem, old_interleave, car_dur, minor_version, conv_type, nb_tsel_acts, program_number, bitstream_switching_mode, dump_nal, time_shift_depth;
+ GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_INBAND;
+ u32 i, stat_level, hint_flags, info_track_id, import_flags, nb_add, nb_cat, ismaCrypt, agg_samples, nb_sdp_ex, max_ptime, raw_sample_num, split_size, nb_meta_act, nb_track_act, rtp_rate, major_brand, nb_alt_brand_add, nb_alt_brand_rem, old_interleave, car_dur, minor_version, conv_type, nb_tsel_acts, program_number, dump_nal, time_shift_depth, dash_dynamic;
Bool HintIt, needSave, FullInter, Frag, HintInter, dump_std, dump_rtp, dump_mode, regular_iod, trackID, remove_sys_tracks, remove_hint, force_new, remove_root_od, import_subtitle, dump_chap;
- Bool print_sdp, print_info, open_edit, track_dump_type, dump_isom, dump_cr, force_ocr, encode, do_log, do_flat, dump_srt, dump_ttxt, dump_timestamps, do_saf, dump_m2ts, dump_cart, do_hash, verbose, force_cat, align_cat, pack_wgt, single_group, dash_dynamic, dash_live;
+ Bool print_sdp, print_info, open_edit, track_dump_type, dump_isom, dump_cr, force_ocr, encode, do_log, do_flat, dump_srt, dump_ttxt, dump_timestamps, do_saf, dump_m2ts, dump_cart, do_hash, verbose, force_cat, align_cat, pack_wgt, single_group, dash_live;
char *inName, *outName, *arg, *mediaSource, *tmpdir, *input_ctx, *output_ctx, *drm_file, *avi2raw, *cprt, *chap_file, *pes_dump, *itunes_tags, *pack_file, *raw_cat, *seg_name, *dash_ctx_file;
char **mpd_base_urls = NULL;
@@ -1379,8 +1390,8 @@ int mp4boxMain(int argc, char **argv)
dump_nal = 0;
FullInter = HintInter = encode = do_log = old_interleave = do_saf = do_hash = verbose = 0;
dump_mode = Frag = force_ocr = remove_sys_tracks = agg_samples = remove_hint = keep_sys_tracks = remove_root_od = single_group = 0;
- conv_type = HintIt = needSave = print_sdp = print_info = regular_iod = dump_std = open_edit = dump_isom = dump_rtp = dump_cr = dump_chap = dump_srt = dump_ttxt = force_new = dump_timestamps = dump_m2ts = dump_cart = import_subtitle = force_cat = pack_wgt = dash_dynamic = dash_live = 0;
- bitstream_switching_mode = 1;
+ conv_type = HintIt = needSave = print_sdp = print_info = regular_iod = dump_std = open_edit = dump_isom = dump_rtp = dump_cr = dump_chap = dump_srt = dump_ttxt = force_new = dump_timestamps = dump_m2ts = dump_cart = import_subtitle = force_cat = pack_wgt = dash_live = 0;
+ dash_dynamic = 0;
/*align cat is the new default behaviour for -cat*/
align_cat = 1;
subsegs_per_sidx = 0;
@@ -1468,6 +1479,12 @@ int mp4boxMain(int argc, char **argv)
trackID = atoi(argv[i+1]);
i++;
}
+ else if (!stricmp(arg, "-raw-layer")) {
+ CHECK_NEXT_ARG
+ track_dump_type = GF_EXPORT_NATIVE | GF_EXPORT_SVC_LAYER;
+ trackID = atoi(argv[i+1]);
+ i++;
+ }
else if (!stricmp(arg, "-qcp")) {
CHECK_NEXT_ARG
track_dump_type = GF_EXPORT_NATIVE | GF_EXPORT_USE_QCP;
@@ -1623,6 +1640,7 @@ int mp4boxMain(int argc, char **argv)
else if (!stricmp(arg, "-isma")) { conv_type = GF_ISOM_CONV_TYPE_ISMA; open_edit = 1; }
else if (!stricmp(arg, "-3gp")) { conv_type = GF_ISOM_CONV_TYPE_3GPP; open_edit = 1; }
else if (!stricmp(arg, "-ipod")) { conv_type = GF_ISOM_CONV_TYPE_IPOD; open_edit = 1; }
+ else if (!stricmp(arg, "-psp")) { conv_type = GF_ISOM_CONV_TYPE_PSP; open_edit = 1; }
else if (!stricmp(arg, "-ismax")) { conv_type = GF_ISOM_CONV_TYPE_ISMA_EX; open_edit = 1; }
else if (!stricmp(arg, "-no-sys") || !stricmp(arg, "-nosys")) { remove_sys_tracks = 1; open_edit = 1; }
@@ -1685,14 +1703,16 @@ int mp4boxMain(int argc, char **argv)
i++;
} else if (!stricmp(arg, "-bs-switching")) {
CHECK_NEXT_ARG
- if (!stricmp(argv[i+1], "no") || !stricmp(argv[i+1], "off")) bitstream_switching_mode = 0;
- else if (!stricmp(argv[i+1], "single")) bitstream_switching_mode = 2;
- else bitstream_switching_mode = 1;
+ if (!stricmp(argv[i+1], "no") || !stricmp(argv[i+1], "off")) bitstream_switching_mode = GF_DASH_BSMODE_NONE;
+ else if (!stricmp(argv[i+1], "merge")) bitstream_switching_mode = GF_DASH_BSMODE_MERGED;
+ else if (!stricmp(argv[i+1], "single")) bitstream_switching_mode = GF_DASH_BSMODE_SINGLE;
+ else if (!stricmp(argv[i+1], "single_merge")) bitstream_switching_mode = GF_DASH_BSMODE_SINGLE_MERGED;
+ else bitstream_switching_mode = GF_DASH_BSMODE_INBAND;
i++;
}
else if (!stricmp(arg, "-dynamic")) { dash_dynamic = 1; }
- else if (!strnicmp(arg, "-dash-live", 10)) {
- dash_dynamic = 1;
+ else if (!strnicmp(arg, "-dash-live", 10) || !strnicmp(arg, "-ddbg-live", 10)) {
+ dash_dynamic = !strnicmp(arg, "-ddbg-live", 10) ? 2 : 1;
dash_live = 1;
if (arg[10]=='=') {
dash_ctx_file = arg+11;
@@ -1876,7 +1896,8 @@ int mp4boxMain(int argc, char **argv)
tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1));
tracks[nb_track_act].act_type = 4;
- strcpy(szTK, argv[i+1]);
+ assert(strlen(argv[i+1])+1 <= sizeof(szTK));
+ strncpy(szTK, argv[i+1], sizeof(szTK));
ext = strchr(szTK, '=');
if (!ext) {
fprintf(stderr, "Bad format for track par - expecting ID=PAR_NUM:PAR_DEN got %s\n", argv[i+1]);
@@ -1885,7 +1906,13 @@ int mp4boxMain(int argc, char **argv)
if (!stricmp(ext+1, "none")) {
tracks[nb_track_act].par_num = tracks[nb_track_act].par_den = -1;
} else {
- sscanf(ext+1, "%d:%d", &tracks[nb_track_act].par_num, &tracks[nb_track_act].par_den);
+ sscanf(ext+1, "%d", &tracks[nb_track_act].par_num);
+ ext = strchr(ext+1, ':');
+ if (!ext) {
+ fprintf(stderr, "Bad format for track par - expecting ID=PAR_NUM:PAR_DEN got %s\n", argv[i+1]);
+ MP4BOX_EXIT_WITH_CODE(1);
+ }
+ sscanf(ext+1, "%d", &tracks[nb_track_act].par_den);
}
ext[0] = 0;
tracks[nb_track_act].trackID = atoi(szTK);
@@ -2542,11 +2569,30 @@ int mp4boxMain(int argc, char **argv)
}
for (i=0; i<(u32) argc; i++) {
if (!strcmp(argv[i], "-add")) {
- e = import_file(file, argv[i+1], import_flags, import_fps, agg_samples);
+ char *src = argv[i+1];
+
+ e = import_file(file, src, import_flags, import_fps, agg_samples);
if (e) {
- fprintf(stderr, "Error importing %s: %s\n", argv[i+1], gf_error_to_string(e));
- gf_isom_delete(file);
- MP4BOX_EXIT_WITH_CODE(1);
+ while (src) {
+ char *sep = strchr(src, '+');
+ if (sep) sep[0] = 0;
+
+ e = import_file(file, src, import_flags, import_fps, agg_samples);
+
+ if (sep) {
+ sep[0] = '+';
+ src = sep+1;
+ } else {
+ src= NULL;
+ }
+ if (e)
+ break;
+ }
+ if (e) {
+ fprintf(stderr, "Error importing %s: %s\n", argv[i+1], gf_error_to_string(e));
+ gf_isom_delete(file);
+ MP4BOX_EXIT_WITH_CODE(1);
+ }
}
i++;
}
@@ -2706,14 +2752,19 @@ int mp4boxMain(int argc, char **argv)
char c = (char) gf_prompt_get_char();
if (c=='q') break;
}
- fprintf(stderr, "sleep for %d ms\n", sleep_for);
- gf_sleep(sleep_for);
+ if (sleep_for) {
+ if (dash_dynamic != 2) {
+ fprintf(stderr, "sleep for %d ms\n", sleep_for);
+ gf_sleep(sleep_for);
+ }
+ }
} else {
break;
}
}
if (dash_ctx) gf_cfg_del(dash_ctx);
+ if (e) fprintf(stderr, "Error DASHing file: %s\n", gf_error_to_string(e));
gf_sys_close();
MP4BOX_EXIT_WITH_CODE( (e!=GF_OK) ? 1 : 0 );
@@ -3172,6 +3223,8 @@ int mp4boxMain(int argc, char **argv)
switch (gf_isom_get_media_subtype(file, i+1, 1)) {
case GF_ISOM_SUBTYPE_AVC_H264:
case GF_ISOM_SUBTYPE_AVC2_H264:
+ case GF_ISOM_SUBTYPE_AVC3_H264:
+ case GF_ISOM_SUBTYPE_AVC4_H264:
fprintf(stderr, "Forcing AVC/H264 SAR to 1:1...\n");
gf_media_change_par(file, i+1, 1, 1);
break;
@@ -3405,8 +3458,8 @@ int mp4boxMain(int argc, char **argv)
n = t = 0;
memset(_t, 0, sizeof(char)*8);
tlen = (itag==GF_ISOM_ITUNE_DISK) ? 6 : 8;
- if (sscanf(val, "%u/%u", &n, &t) == 2) { _t[3]=n; _t[5]=t;}
- else if (sscanf(val, "%u", &n) == 1) { _t[3]=n;}
+ if (sscanf(val, "%u/%u", &n, &t) == 2) { _t[3]=n; _t[2]=n>>8; _t[5]=t; _t[4]=t>>8; }
+ else if (sscanf(val, "%u", &n) == 1) { _t[3]=n; _t[2]=n>>8;}
else tlen = 0;
if (tlen) gf_isom_apple_set_tag(file, itag, _t, tlen);
}
diff --git a/applications/mp4client/main.c b/applications/mp4client/main.c
index caa330b..7fcd459 100644
--- a/applications/mp4client/main.c
+++ b/applications/mp4client/main.c
@@ -1155,7 +1155,13 @@ int main (int argc, char **argv)
fprintf(stderr, "Loading modules\n");
str = gf_cfg_get_key(cfg_file, "General", "ModulesDirectory");
- assert( str );
+ if (! str ) {
+ fprintf(stderr, "Mmodule directory not found - check the configuration file exit and the \"ModulesDirectory\" key is set\n");
+ gf_cfg_del(cfg_file);
+ gf_sys_close();
+ if (logfile) fclose(logfile);
+ return 1;
+ }
user.modules = gf_modules_new((const unsigned char *) str, cfg_file);
if (user.modules) i = gf_modules_get_count(user.modules);
diff --git a/applications/ts2hds/f4m.c b/applications/ts2hds/f4m.c
index b09aa49..92b31b6 100644
--- a/applications/ts2hds/f4m.c
+++ b/applications/ts2hds/f4m.c
@@ -29,7 +29,7 @@
#include
-#define ADOBE_INLINED_BOOTSTRAP
+//#define ADOBE_INLINED_BOOTSTRAP
struct __tag_adobe_stream
{
@@ -47,6 +47,20 @@ struct __tag_adobe_multirate
GF_List *streams;
};
+static GF_Err adobe_gen_stream_manifest(AdobeStream *as)
+{
+ fprintf(as->f, "\n");
+ fprintf(as->f, "\n");
+ fprintf(as->f, "%s\n", as->id);
+ if (as->base_url)
+ fprintf(as->f, "%s\n", as->base_url);
+ fprintf(as->f, "\n", as->id, as->bitrate, as->id, as->bitrate);
+ fprintf(as->f, "\n", as->id, as->bitrate, as->bitrate, as->id, as->bitrate);
+ fprintf(as->f, "\n");
+
+ return GF_OK;
+}
+
AdobeMultirate *adobe_alloc_multirate_manifest(char *id)
{
AdobeMultirate *am = gf_calloc(1, sizeof(AdobeMultirate));
@@ -70,6 +84,16 @@ AdobeMultirate *adobe_alloc_multirate_manifest(char *id)
AdobeStream *as = gf_calloc(1, sizeof(AdobeStream));
as->id = "HD";
as->bitrate = 100;
+ sprintf(filename, "%s_%s_%d.f4m", am->id, as->id, as->bitrate);
+ as->f = fopen(filename, "wt");
+ if (!as->f) {
+ fprintf(stderr, "Couldn't create Adobe stream manifest file: %s\n", filename);
+ assert(0);
+ gf_list_del(am->streams);
+ gf_free(as);
+ gf_free(am);
+ return NULL;
+ }
gf_list_add(am->streams, as);
}
@@ -86,6 +110,8 @@ void adobe_free_multirate_manifest(AdobeMultirate *am)
for (i=0; istreams); i++) {
AdobeStream *as = gf_list_get(am->streams, i);
assert(as);
+ if (as->f)
+ fclose(as->f);
//TODO: base_url and id may be stored as gf_strdup in the future
gf_list_rem(am->streams, i);
gf_free(as);
@@ -97,6 +123,7 @@ void adobe_free_multirate_manifest(AdobeMultirate *am)
GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t bootstrap_size)
{
+ GF_Err e;
u32 i;
#ifdef ADOBE_INLINED_BOOTSTRAP
char bootstrap64[GF_MAX_PATH];
@@ -104,7 +131,7 @@ GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t
#endif
fprintf(am->f, "\n");
- fprintf(am->f, "\n");
+ fprintf(am->f, "\n");
fprintf(am->f, "%s\n", am->id);
fprintf(am->f, "%s\n", am->base_url);
fprintf(am->f, "live\n");
@@ -123,7 +150,6 @@ GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t
}
fprintf(am->f, "\n\n");
#else
- fprintf(am->f, "\n", as->id, as->bitrate, as->id, as->bitrate);
{
char filename[GF_MAX_PATH];
FILE *bstfile;
@@ -133,7 +159,13 @@ GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t
fclose(bstfile);
}
#endif
- fprintf(am->f, "\n", am->id, as->id, as->bitrate, as->bitrate, as->id, as->bitrate);
+ e = adobe_gen_stream_manifest(as);
+ if (!e) {
+ if (!am->base_url && !as->base_url)
+ fprintf(stderr, "Warning: no base_url specified\n");
+
+ fprintf(am->f, "\n", am->id, as->id, as->bitrate, as->bitrate);
+ }
}
fprintf(am->f, "\n");
diff --git a/applications/ts2hds/f4v.c b/applications/ts2hds/f4v.c
index f49284b..9a80b65 100644
--- a/applications/ts2hds/f4v.c
+++ b/applications/ts2hds/f4v.c
@@ -61,7 +61,7 @@ GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx)
afra->entry_count = 1;
ae->time = init_seg_time;
- ae->offset = 31663;
+ ae->offset = 3999;
gf_list_add(afra->local_access_entries, ae);
afra->global_entries = 0;
@@ -101,7 +101,7 @@ GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx)
asrt->flags = 0;
asrt->segment_run_entry_count = 1;
{
- asre->first_segment = 1;
+ asre->first_segment = ctx->segnum;
asre->fragment_per_segment = 1;
}
e = gf_list_add(asrt->segment_run_entry_table, asre);
@@ -124,7 +124,7 @@ GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx)
afrt->type = GF_4CC('a', 'f', 'r', 't');
afrt->version = 0;
afrt->flags = 0;
- afrt->timescale = 1000;
+ afrt->timescale = gf_isom_get_timescale(isom_file);
afrt->fragment_run_entry_count = 1;
{
afre->first_fragment = 1;
diff --git a/applications/ts2hds/main.c b/applications/ts2hds/main.c
index 0e98a52..09fc32b 100644
--- a/applications/ts2hds/main.c
+++ b/applications/ts2hds/main.c
@@ -141,8 +141,7 @@ int main(int argc, char **argv)
e = GF_OK;
memset(&ctx, 0, sizeof(ctx));
- ctx.multirate_manifest = adobe_alloc_multirate_manifest(output);
- ctx.curr_time = 6000;
+ ctx.curr_time = 0;
ctx.segnum = 1;
/*********************************************/
@@ -153,6 +152,8 @@ int main(int argc, char **argv)
goto exit;
}
+ ctx.multirate_manifest = adobe_alloc_multirate_manifest(output);
+
#if 0 /*'moov' conversion tests*/
{
char metamoov64[GF_MAX_PATH];
diff --git a/bin/smartphone 2003 (armv4)/release/install/gpac.inf b/bin/smartphone 2003 (armv4)/release/install/gpac.inf
index 0bce1e0..870c6ea 100644
--- a/bin/smartphone 2003 (armv4)/release/install/gpac.inf
+++ b/bin/smartphone 2003 (armv4)/release/install/gpac.inf
@@ -46,12 +46,7 @@ js32.dll = 1
gm_aac_in.dll = 1
gm_bifs_dec.dll = 1
gm_ctx_load.dll = 1
-gm_dummy_in.dll = 1
-gm_ffmpeg_in.dll = 1
-avcodec-52.dll = 1
-avformat-52.dll = 1
-avutil-50.dll = 1
-swscale-0.dll = 1
+gm_dummy_in.dll = 1
gm_ft_font.dll = 1
gm_gapi.dll = 1
gm_gpac_js.dll = 1
@@ -71,7 +66,12 @@ gm_wav_out.dll = 1
gm_widgetman.dll = 1
gm_xvid_dec.dll = 1
gm_ogg.dll = 1
-
+;commenting out ffmpeg since we no longer have a recent version (and no one uses smartphone 2003 anymore ...)
+;gm_ffmpeg_in.dll = 1
+;avcodec-52.dll = 1
+;avformat-52.dll = 1
+;avutil-50.dll = 1
+;swscale-0.dll = 1
;==================================================
diff --git a/configure b/configure
index e3220ac..a5ca4e1 100755
--- a/configure
+++ b/configure
@@ -18,13 +18,7 @@ fi
#remember the ./configure command line
-for v in "$@"; do
- r="${v#*=}"
- l="${v%$r}"
- test "$r" = "${r#* }" || r="'$r'"
- GPAC_CONFIGURATION="${GPAC_CONFIGURATION# } ${l}${r}"
-done
-
+GPAC_CONFIGURATION="$@"
TMPC="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.c"
TMPH="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.h"
@@ -150,6 +144,7 @@ disable_isoff_write="no"
disable_isoff_frag="no"
disable_isoff_hint="no"
disable_isoff_frag="no"
+disable_isoff_hds="no"
disable_streaming="no"
disable_player="no"
disable_scenegraph="no"
@@ -283,6 +278,7 @@ Configuration options for libgpac - all options can be enabled with --enable-opt
--disable-isoff-write disable ISO File Format edit/write
--disable-isoff-hint disable ISO File Format hinting
--disable-isoff-frag disable fragments in ISO File Format
+ --disable-isoff-hds disable HDS support in ISO File Format
--disable-streaming disable RTP/RTSP/SDP
--disable-dvbx disable DVB-specific tools (MPE, FEC, DSM-CC)
--disable-vobsub disable VobSub support
@@ -294,7 +290,7 @@ Configuration options for libgpac - all options can be enabled with --enable-opt
Extra libraries configuration. You can turn a libray off or force using the local version in gpac/extra_lib/
--use-js=OPT force SpiderMonkey ECMAScript OPT=[no,local]
--use-ft=OPT force FreeType OPT=[no,local]
- --use-zlib=OPT force ZLIB OPT=[no,local]
+ --use-zlib=OPT force ZLIB OPT=[no,system,local]
--use-jpeg=OPT force JPEG OPT=[no,local]
--use-png=OPT force PNG OPT=[no,local]
--use-faad=OPT force FAAD OPT=[no,local]
@@ -653,7 +649,7 @@ if test "$cross_prefix" = "" ; then
has_zlib="system"
fi
fi
-if test "$has_zlib" = "no" ; then
+if test "$has_zlib" = "force-no" ; then
if $cc -o $TMPO $TMPC -I"$local_inc/zlib" -L$local_lib -lz 2> /dev/null ; then
has_zlib="local"
fi
@@ -869,6 +865,8 @@ int main( void ) { jsval *vp; JSObject *obj = JS_NewObjectForConstructor(c, vp);
EOF
if $cc -o $TMPO $TMPC $js_flags $LDFLAGS $js_lib 2> /dev/null ; then
js_flags="-DUSE_FFDEV_12 $js_flags"
+ elif grep JSMutableHandleValue $js_inc/jsapi.h > /dev/null 2>&1 ; then
+ js_flags="-DUSE_FFDEV_17 $js_flags"
elif ! grep JS_ConstructObject $js_inc/jsapi.h > /dev/null 2>&1 ; then
js_flags="-DUSE_FFDEV_16 $js_flags"
elif grep JSHandleObject $js_inc/jsapi.h > /dev/null 2>&1 ; then
@@ -1713,8 +1711,13 @@ for opt do
echo
fi
fi
+ has_zlib=$tmp_has_zlib
+ elif test "$tmp_has_zlib" = "no" ; then
+ echo
+ echo "WARNING!! : you have forced not to use ZLIB. This will disable some core functionalities of GPAC."
+ echo
+ has_zlib="force-no"
fi
- has_png=$tmp_has_png
;;
--use-ogg=*) has_ogg=${opt#--use-ogg=}
;;
@@ -1729,7 +1732,7 @@ for opt do
--enable-pulseaudio=*) has_pulseaudio="yes"
;;
- --disable-all) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_mcrypt="yes"; disable_isoff="yes"; disable_isoff_write="yes"; disable_isoff_hint="yes"; disable_isoff_frag="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"
+ --disable-all) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_mcrypt="yes"; disable_isoff="yes"; disable_isoff_write="yes"; disable_isoff_hint="yes"; disable_isoff_frag="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_isoff_hds = "yes"
;;
--disable-3d) disable_3d="yes"
@@ -1866,6 +1869,10 @@ for opt do
;;
--enable-isoff-frag) disable_isoff_frag="no"
;;
+ --disable-isoff-hds) disable_isoff_hds="yes"
+ ;;
+ --enable-isoff-hds) disable_isoff_hds="no"
+ ;;
--disable-streaming) disable_streaming="yes"
;;
--enable-streaming) disable_streaming="no"
@@ -2405,6 +2412,11 @@ if test "$disable_isoff_frag" = "yes" ; then
echo "ISO File Format fragments disabled"
echo "#define GPAC_DISABLE_ISOM_FRAGMENTS" >> $TMPH
fi
+if test "$disable_isoff_hds" = "yes" ; then
+ echo "ISO File Format Adobe HDS disabled"
+ echo "#define GPAC_DISABLE_ISOM_ADOBE" >> $TMPH
+fi
+
if test "$disable_streaming" = "yes" ; then
echo "RTP/RTSP/SDP streaming disabled"
echo "#define GPAC_DISABLE_STREAMING" >> $TMPH
@@ -2692,6 +2704,9 @@ else
echo "#define GPAC_HAS_SPIDERMONKEY" >> $TMPH
fi
echo "CONFIG_ZLIB=$has_zlib" >> config.mak
+if test "$has_zlib" = "no" ; then
+ echo "#define GPAC_DISABLE_ZLIB" >> $TMPH
+fi
echo "CONFIG_FT=$has_ft" >> config.mak
echo "CONFIG_JPEG=$has_jpeg" >> config.mak
@@ -2765,6 +2780,7 @@ echo "DISABLE_CORE_TOOLS=$disable_core_tools" >> config.mak
echo "DISABLE_OD_DUMP=$disable_od_dump" >> config.mak
echo "DISABLE_OD_PARSE=$disable_od_parse" >> config.mak
echo "MINIMAL_OD=$disable_od" >> config.mak
+echo "DISABLE_ISOM_ADOBE=$disable_isoff_hds" >> config.mak
if test "$disable_parsers" = "yes" ; then
disable_m2ts_mux="yes"
diff --git a/doc/configuration.html b/doc/configuration.html
index 1062baf..1eae4e4 100644
--- a/doc/configuration.html
+++ b/doc/configuration.html
@@ -10,7 +10,7 @@
GPAC Configuration file documentation
Version 0.5.0
-Last Modified $LastChangedDate: 2012-11-15 18:57:26 +0000 (Thu, 15 Nov 2012) $
+Last Modified $LastChangedDate: 2012-12-06 19:08:32 +0000 (Thu, 06 Dec 2012) $
@@ -728,9 +728,12 @@ For debug purposes, instructs the player to switch representation every N segmen
DisableSwitching [value: yes, no]
Disables automatic adaptation logic. Default is no
-KeepFiles [value: yes, no]
+MemoryStorage [value: yes, no]
+
+Files are only stored in memory and destroyed after playback, no disk IO is used. Default is no
+UseMaxResolution [value: yes, no]
-Forces files to be kept on disk. Default is no
+Forces the player to set the output video resolution to the max resolution available instead of resizing the window. Default is yes
StartRepresentation [value: minBandwidth, maxBandwidth, minQuality, maxQuality]
Instructs the DASH client to start playing the indicated representation before doing any switching. Default is minBandwidth.
diff --git a/include/gpac/avparse.h b/include/gpac/avparse.h
index 3bd79e6..c8b4f29 100644
--- a/include/gpac/avparse.h
+++ b/include/gpac/avparse.h
@@ -220,6 +220,7 @@ u32 gf_ac3_get_channels(u32 acmod);
u32 gf_ac3_get_bitrate(u32 brcode);
GF_Err gf_avc_get_sps_info(char *sps, u32 sps_size, u32 *sps_id, u32 *width, u32 *height, s32 *par_n, s32 *par_d);
+GF_Err gf_avc_get_pps_info(char *pps, u32 pps_size, u32 *pps_id, u32 *sps_id);
const char *gf_avc_get_profile_name(u8 video_prof);
#endif /*GPAC_DISABLE_AV_PARSERS*/
diff --git a/include/gpac/configuration.h b/include/gpac/configuration.h
index 320d552..ae829b5 100644
--- a/include/gpac/configuration.h
+++ b/include/gpac/configuration.h
@@ -58,6 +58,9 @@
#define MOZILLA_1_8_BRANCH
#endif
+/*zlib enabled*/
+//#define GPAC_DISABLE_ZLIB
+
/*libjpeg enabled*/
#define GPAC_HAS_JPEG
diff --git a/include/gpac/constants.h b/include/gpac/constants.h
index eab19e1..21409cb 100644
--- a/include/gpac/constants.h
+++ b/include/gpac/constants.h
@@ -268,6 +268,8 @@ enum
GPAC_OTI_VIDEO_AVC = 0x21,
/*!OTI for AVC Parameter sets streams*/
GPAC_OTI_VIDEO_AVC_PS = 0x22,
+ /*!OTI for HEVC video */
+ GPAC_OTI_VIDEO_HEVC = 0x23,
/*!OTI for MPEG-4 AAC streams*/
GPAC_OTI_AUDIO_AAC_MPEG4 = 0x40,
@@ -563,6 +565,40 @@ enum
#define GF_AVC_TYPE2_SI 9
+
+/*HEVC NAL unit types*/
+enum {
+ GF_HEVC_NALU_SLICE_TRAIL_N = 0,
+ GF_HEVC_NALU_SLICE_TRAIL_R = 1,
+ GF_HEVC_NALU_SLICE_TSA_N = 2,
+ GF_HEVC_NALU_SLICE_TSA_R = 3,
+ GF_HEVC_NALU_SLICE_STSA_N = 4,
+ GF_HEVC_NALU_SLICE_STSA_R = 5,
+ GF_HEVC_NALU_SLICE_RADL_N = 6,
+ GF_HEVC_NALU_SLICE_RADL_R = 7,
+ GF_HEVC_NALU_SLICE_RASL_N = 8,
+ GF_HEVC_NALU_SLICE_RASL_R = 9,
+
+ GF_HEVC_NALU_SLICE_BLA_W_LP = 16,
+ GF_HEVC_NALU_SLICE_BLA_W_DLP = 17,
+ GF_HEVC_NALU_SLICE_BLA_N_LP = 18,
+
+ GF_HEVC_NALU_SLICE_IDR_W_DLP = 19,
+ GF_HEVC_NALU_SLICE_IDR_N_LP = 20,
+ GF_HEVC_NALU_SLICE_CRA = 21,
+
+ GF_HEVC_NALU_VID_PARAM = 32,
+ GF_HEVC_NALU_SEQ_PARAM = 33,
+ GF_HEVC_NALU_PIC_PARAM = 34,
+ GF_HEVC_NALU_ACCESS_UNIT = 35,
+ GF_HEVC_NALU_END_OF_SEQ = 36,
+ GF_HEVC_NALU_END_OF_STREAM = 37,
+ GF_HEVC_NALU_FILLER_DATA = 38,
+ GF_HEVC_NALU_SEI_PREFIX = 39,
+ GF_HEVC_NALU_SEI_SUFFIX = 40,
+};
+
+
/*rate sizes - note that these sizes INCLUDE the rate_type header byte*/
static const unsigned int GF_QCELP_RATE_TO_SIZE [] = {0, 1, 1, 4, 2, 8, 3, 17, 4, 35, 5, 8, 14, 1};
static const unsigned int GF_QCELP_RATE_TO_SIZE_NB = 7;
diff --git a/include/gpac/dash.h b/include/gpac/dash.h
index 2f865cf..828ea7d 100644
--- a/include/gpac/dash.h
+++ b/include/gpac/dash.h
@@ -83,7 +83,7 @@ struct _gf_dash_io
/*resetup the file session with a new resource to get - this allows persistent connection usage with HTTP servers*/
GF_Err (*setup_from_url)(GF_DASHFileIO *dashio, GF_DASHFileIOSession session, const char *url);
/*set download range for the file session*/
- GF_Err (*set_range)(GF_DASHFileIO *dashio, GF_DASHFileIOSession session, u64 start_range, u64 end_range);
+ GF_Err (*set_range)(GF_DASHFileIO *dashio, GF_DASHFileIOSession session, u64 start_range, u64 end_range, Bool discontinue_cache);
/*initialize the file session - all the headers shall be fetched before returning*/
GF_Err (*init)(GF_DASHFileIO *dashio, GF_DASHFileIOSession session);
/*download the content - synchronous call: all the file shall be fetched before returning*/
@@ -142,7 +142,7 @@ const char *gf_dash_get_url(GF_DashClient *dash);
void gf_dash_get_info(GF_DashClient *dash, const char **title, const char **source);
/*switches quality up or down*/
-void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up);
+void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up, Bool force_immediate_switch);
/*indicates whether the DASH client is running or not. For the moment, the DASH client is always run by an internal thread*/
Bool gf_dash_is_running(GF_DashClient *dash);
@@ -174,11 +174,13 @@ const char *gf_dash_group_get_segment_mime(GF_DashClient *dash, u32 idx);
const char *gf_dash_group_get_segment_init_url(GF_DashClient *dash, u32 idx, u64 *start_range, u64 *end_range);
/*returns the URL and byte range of the next media resource to play in this group.
-If switching occured and no bitstream switching is possible, also set the url and byte range of the media file required to intialize the playback
+If switching occured, sets switching_index to the new representation index.
+If no bitstream switching is possible, also set the url and byte range of the media file required to intialize
+the playback of the next segment
original_url is optional and may be used to het the URI of the segment
*/
GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, const char **url, u64 *start_range, u64 *end_range,
- const char **switching_url, u64 *switching_start_range, u64 *switching_end_range,
+ s32 *switching_index, const char **switching_url, u64 *switching_start_range, u64 *switching_end_range,
const char **original_url);
/*discards the first media resource in the queue of this group*/
void gf_dash_group_discard_segment(GF_DashClient *dash, u32 idx);
@@ -209,6 +211,8 @@ void gf_dash_seek(GF_DashClient *dash, Double start_range);
Double gf_dash_get_playback_start_range(GF_DashClient *dash);
/*when seeking, this flag is set when the seek is outside of the previously playing segment.*/
Bool gf_dash_group_segment_switch_forced(GF_DashClient *dash, u32 idx);
+/*get video info for this group if video*/
+GF_Err gf_dash_group_get_video_info(GF_DashClient *dash, u32 idx, u32 *max_width, u32 *max_height);
/*returns the start_time of the first segment in the queue (usually the one being played)*/
Double gf_dash_group_current_segment_start_time(GF_DashClient *dash, u32 idx);
@@ -216,6 +220,9 @@ Double gf_dash_group_current_segment_start_time(GF_DashClient *dash, u32 idx);
/*allow reloading of MPD on the local file system - usefull for testing live generators*/
void gf_dash_allow_local_mpd_update(GF_DashClient *dash, Bool allow_local_mpd_update);
+/*gets media info for representation*/
+GF_Err gf_dash_group_get_representation_info(GF_DashClient *dash, u32 idx, u32 representation_idx, u32 *width, u32 *height, u32 *audio_samplerate, u32 *bandwidth, const char **codecs);
+
#endif //GPAC_DISABLE_DASH_CLIENT
diff --git a/include/gpac/download.h b/include/gpac/download.h
index a28f9d2..b94b95e 100644
--- a/include/gpac/download.h
+++ b/include/gpac/download.h
@@ -170,6 +170,9 @@ extern "C" {
GF_NETIO_SESSION_NOT_CACHED = 1<<1,
/*indicates that the connection to the server should be kept once the download is successfully completed*/
GF_NETIO_SESSION_PERSISTENT = 1<<2,
+ /*file is stored in memory, and the cache name is set to gpac://%u@%p, where %d is the size in bytes and %d is the the pointer to the memory.
+ Memory cached files are destroyed upon downloader destruction*/
+ GF_NETIO_SESSION_MEMORY_CACHE = 1<<3,
};
@@ -318,9 +321,10 @@ extern "C" {
*\param sess the download session
*\param start_range HTTP download start range in byte
*\param end_range HTTP download end range in byte
+ *\param discontinue If set, forces a new cache entry if byte range are not continuous. Otherwise a single cache entry is used to reconstruct the file
*\note this can only be used when the session is not threaded
*/
- GF_Err gf_dm_sess_set_range(GF_DownloadSession *sess, u64 start_range, u64 end_range);
+ GF_Err gf_dm_sess_set_range(GF_DownloadSession *sess, u64 start_range, u64 end_range, Bool discontinue_cache);
/*!
*\brief get cache file name
*
diff --git a/include/gpac/internal/compositor_dev.h b/include/gpac/internal/compositor_dev.h
index afee21f..95f7ee0 100644
--- a/include/gpac/internal/compositor_dev.h
+++ b/include/gpac/internal/compositor_dev.h
@@ -246,7 +246,7 @@ struct __tag_compositor
/*options*/
u32 aspect_ratio, antiAlias, texture_text_mode;
Bool high_speed, stress_mode;
- Bool force_opengl_2d;
+ Bool force_opengl_2d, was_opengl;
#ifdef OPENGL_RASTER
Bool opengl_raster;
#endif
@@ -331,7 +331,7 @@ struct __tag_compositor
/*screen buffer for direct access*/
GF_VideoSurface hw_surface;
/*output buffer is configured in video memory*/
- Bool video_memory, request_video_memory;
+ Bool video_memory, request_video_memory, was_system_memory;
/*indicate if overlays were prezsent in the previous frame*/
Bool last_had_overlays;
GF_RasterCallback raster_callbacks;
diff --git a/include/gpac/internal/isomedia_dev.h b/include/gpac/internal/isomedia_dev.h
index 151cf0b..eac3380 100644
--- a/include/gpac/internal/isomedia_dev.h
+++ b/include/gpac/internal/isomedia_dev.h
@@ -198,8 +198,13 @@ enum
GF_ISOM_BOX_TYPE_PASP = GF_4CC( 'p', 'a', 's', 'p' ),
GF_ISOM_BOX_TYPE_AVC1 = GF_4CC( 'a', 'v', 'c', '1' ),
GF_ISOM_BOX_TYPE_AVC2 = GF_4CC( 'a', 'v', 'c', '2' ),
+ GF_ISOM_BOX_TYPE_AVC3 = GF_4CC( 'a', 'v', 'c', '3' ),
+ GF_ISOM_BOX_TYPE_AVC4 = GF_4CC( 'a', 'v', 'c', '4' ),
GF_ISOM_BOX_TYPE_SVCC = GF_4CC( 's', 'v', 'c', 'C' ),
GF_ISOM_BOX_TYPE_SVC1 = GF_4CC( 's', 'v', 'c', '1' ),
+ GF_ISOM_BOX_TYPE_HVCC = GF_4CC( 'h', 'v', 'c', 'C' ),
+ GF_ISOM_BOX_TYPE_HVC1 = GF_4CC( 'h', 'v', 'c', '1' ),
+ GF_ISOM_BOX_TYPE_HEV1 = GF_4CC( 'h', 'e', 'v', '1' ),
/*LASeR extension*/
GF_ISOM_BOX_TYPE_LSRC = GF_4CC( 'l', 's', 'r', 'C' ),
@@ -528,6 +533,13 @@ typedef struct
char *name;
/*private for editing*/
Bool is_unpacked;
+ /*private for checking dependency*/
+ u32 originalFile;
+ u32 originalID;
+
+ /*private for SVC/MVC extractors resolution*/
+ s32 extractor_mode;
+ Bool has_base_layer;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
u64 dts_at_seg_start;
@@ -788,6 +800,7 @@ typedef struct
GF_SLConfig *slc;
} GF_LASeRSampleEntryBox;
+/*rewrites avcC based on the given esd - this destroys the esd*/
GF_Err LSR_UpdateESD(GF_LASeRSampleEntryBox *lsr, GF_ESD *esd);
typedef struct
@@ -841,6 +854,12 @@ typedef struct
GF_AVCConfig *config;
} GF_AVCConfigurationBox;
+typedef struct
+{
+ GF_ISOM_BOX
+ GF_HEVCConfig *config;
+} GF_HEVCConfigurationBox;
+
typedef struct
{
GF_ISOM_VISUAL_SAMPLE_ENTRY
@@ -851,6 +870,9 @@ typedef struct
/*avc extensions - we merged with regular 'mp4v' box to handle isma E&A signaling of AVC*/
GF_AVCConfigurationBox *avc_config;
GF_AVCConfigurationBox *svc_config;
+ /*hevc extension*/
+ GF_HEVCConfigurationBox *hevc_config;
+
GF_MPEG4BitRateBox *bitrate;
/*ext descriptors*/
GF_MPEG4ExtensionDescriptorsBox *descr;
@@ -861,6 +883,8 @@ typedef struct
} GF_MPEGVisualSampleEntryBox;
+Bool gf_isom_is_nalu_based_entry(GF_MediaBox *mdia, GF_SampleEntryBox *_entry);
+GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 sampleNumber, GF_MPEGVisualSampleEntryBox *entry);
/*this is the default visual sdst (to handle unknown media)*/
typedef struct
@@ -2326,6 +2350,11 @@ GF_Err gf_isom_datamap_add_data(GF_DataMap *ptr, char *data, u32 dataSize);
#define GF_ISOM_GET_FRAG_SYNC(flag) ( ! ( ( (flag) >> 16) & 0x1))
#define GF_ISOM_GET_FRAG_DEG(flag) (flag) & 0x7FFF
+#define GF_ISOM_GET_FRAG_LEAD(flag) ( (flag) >> 26) & 0x3
+#define GF_ISOM_GET_FRAG_DEPENDS(flag) ( (flag) >> 24) & 0x3
+#define GF_ISOM_GET_FRAG_DEPENDED(flag) ( (flag) >> 22) & 0x3
+#define GF_ISOM_GET_FRAG_REDUNDANT(flag) ( (flag) >> 20) & 0x3
+
#define GF_ISOM_GET_FRAG_DEPEND_FLAGS(lead, depends, depended, redundant) ( (lead<<26) | (depends<<24) | (depended<<22) | (redundant<<20) )
#define GF_ISOM_RESET_FRAG_DEPEND_FLAGS(flags) flags = flags & 0xFFFFF
@@ -2416,6 +2445,7 @@ GF_ISOFile *gf_isom_new_movie();
GF_TrackBox *gf_isom_get_track_from_file(GF_ISOFile *the_file, u32 trackNumber);
GF_TrackBox *gf_isom_get_track(GF_MovieBox *moov, u32 trackNumber);
GF_TrackBox *gf_isom_get_track_from_id(GF_MovieBox *moov, u32 trackID);
+GF_TrackBox *gf_isom_get_track_from_original_id(GF_MovieBox *moov, u32 originalID, u32 originalFile);
u32 gf_isom_get_tracknum_from_id(GF_MovieBox *moov, u32 trackID);
/*open a movie*/
GF_ISOFile *gf_isom_open_file(const char *fileName, u32 OpenMode, const char *tmp_dir);
@@ -2444,6 +2474,9 @@ GF_Err Media_RewriteODFrame(GF_MediaBox *mdia, GF_ISOSample *sample);
GF_Err Media_FindDataRef(GF_DataReferenceBox *dref, char *URLname, char *URNname, u32 *dataRefIndex);
Bool Media_IsSelfContained(GF_MediaBox *mdia, u32 StreamDescIndex);
+
+GF_TrackBox *GetTrackbyID(GF_MovieBox *moov, u32 TrackID);
+
/*check the TimeToSample for the given time and return the Sample number
if the entry is not found, return the closest sampleNumber in prevSampleNumber and 0 in sampleNumber
if the DTS required is after all DTSs in the list, set prevSampleNumber and SampleNumber to 0
@@ -2575,8 +2608,11 @@ GF_Err minf_AddBox(GF_Box *s, GF_Box *a);
GF_Err mdia_AddBox(GF_Box *s, GF_Box *a);
GF_Err stbl_AddBox(GF_SampleTableBox *ptr, GF_Box *a);
-GF_Err AVC_UpdateESD(GF_MPEGVisualSampleEntryBox *avc, GF_ESD *esd);
+/*rewrites avcC based on the given esd - this destroys the esd*/
+GF_Err AVC_HEVC_UpdateESD(GF_MPEGVisualSampleEntryBox *avc, GF_ESD *esd);
void AVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *avc);
+void HEVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *avc);
+
GF_Err reftype_AddRefTrack(GF_TrackReferenceTypeBox *ref, u32 trackID, u16 *outRefIndex);
GF_XMLBox *gf_isom_get_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool *is_binary);
@@ -3250,7 +3286,11 @@ GF_Err avcc_Size(GF_Box *s);
GF_Box *avc1_New();
GF_Box *avc2_New();
+GF_Box *avc3_New();
+GF_Box *avc4_New();
GF_Box *svc1_New();
+GF_Box *hvc1_New();
+GF_Box *hev1_New();
GF_Box *m4ds_New();
void m4ds_del(GF_Box *s);
@@ -3846,6 +3886,13 @@ GF_Err cslg_Size(GF_Box *s);
GF_Err cslg_Read(GF_Box *s, GF_BitStream *bs);
GF_Err cslg_dump(GF_Box *a, FILE * trace);
+GF_Box *hvcc_New();
+void hvcc_del(GF_Box *);
+GF_Err hvcc_Write(GF_Box *s, GF_BitStream *bs);
+GF_Err hvcc_Size(GF_Box *s);
+GF_Err hvcc_Read(GF_Box *s, GF_BitStream *bs);
+GF_Err hvcc_dump(GF_Box *a, FILE * trace);
+
#endif /*GPAC_DISABLE_ISOM*/
#ifdef __cplusplus
diff --git a/include/gpac/internal/media_dev.h b/include/gpac/internal/media_dev.h
index 4ff8ab1..daf53d2 100644
--- a/include/gpac/internal/media_dev.h
+++ b/include/gpac/internal/media_dev.h
@@ -49,9 +49,15 @@ GF_Err gf_import_message(GF_MediaImporter *import, GF_Err e, char *format, ...);
/*returns 0 if not a start code, or size of start code (3 or 4 bytes). If start code, bitstream
is positionned AFTER start code*/
-u32 AVC_IsStartCode(GF_BitStream *bs);
+u32 gf_media_nalu_is_start_code(GF_BitStream *bs);
+
/*returns size of chunk between current and next startcode (excluding startcode sizes), 0 if no more startcodes (eos)*/
-u32 AVC_NextStartCode(GF_BitStream *bs);
+u32 gf_media_nalu_next_start_code_bs(GF_BitStream *bs);
+
+/*return nb bytes from current data until the next start code and set the size of the next start code (3 or 4 bytes)
+returns data_len if no startcode found and sets sc_size to 0 (last nal in payload)*/
+u32 gf_media_nalu_next_start_code(u8 *data, u32 data_len, u32 *sc_size);
+
/*returns NAL unit type - bitstream must be sync'ed!!*/
u8 AVC_NALUType(GF_BitStream *bs);
Bool SVC_NALUIsSlice(u8 type);
@@ -133,6 +139,7 @@ typedef struct
u32 slice_group_count; /* num_slice_groups_minus1 + 1*/
/*used to discard repeated SPSs - 0: not parsed, 1 parsed, 2 sent*/
u32 status;
+
} AVC_PPS;
typedef struct
@@ -205,29 +212,163 @@ typedef struct
/*return sps ID or -1 if error*/
-s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps, u32 *vui_flag_pos);
+s32 gf_media_avc_read_sps(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps, u32 *vui_flag_pos);
/*return pps ID or -1 if error*/
-s32 AVC_ReadPictParamSet(char *pps_data, u32 pps_size, AVCState *avc);
+s32 gf_media_avc_read_pps(char *pps_data, u32 pps_size, AVCState *avc);
/*return sps ID or -1 if error*/
-s32 AVC_ReadSeqParamSetExtId(char *spse_data, u32 spse_size);
+s32 gf_media_avc_read_sps_ext(char *spse_data, u32 spse_size);
/*is slice an IDR*/
-Bool AVC_SliceIsIDR(AVCState *avc);
+Bool gf_media_avc_slice_is_IDR(AVCState *avc);
/*is slice containing intra MB only*/
-Bool AVC_SliceIsIntra(AVCState *avc);
+Bool gf_media_avc_slice_is_intra(AVCState *avc);
/*parses NALU, updates avc state and returns:
1 if NALU part of new frame
0 if NALU part of prev frame
-1 if bitstream error
*/
-s32 AVC_ParseNALU(GF_BitStream *bs, u32 nal_hdr, AVCState *avc);
+s32 gf_media_avc_parse_nalu(GF_BitStream *bs, u32 nal_hdr, AVCState *avc);
/*remove SEI messages not allowed in MP4*/
/*nota: 'buffer' remains unmodified but cannot be set const*/
-u32 AVC_ReformatSEI_NALU(char *buffer, u32 nal_size, AVCState *avc);
+u32 gf_media_avc_reformat_sei(char *buffer, u32 nal_size, AVCState *avc);
#ifndef GPAC_DISABLE_ISOM
-GF_Err AVC_ChangePAR(GF_AVCConfig *avcc, s32 ar_n, s32 ar_d);
+GF_Err gf_media_avc_change_par(GF_AVCConfig *avcc, s32 ar_n, s32 ar_d);
#endif
+
+
+typedef struct
+{
+ Bool profile_present_flag, level_present_flag, tier_flag;
+ u8 profile_space;
+ u8 profile_idc;
+ u32 profile_compatibility_flag;
+ u8 level_idc;
+} HEVC_SublayerPTL;
+
+typedef struct
+{
+ u8 profile_space, tier_flag, profile_idc, level_idc;
+ u32 profile_compatibility_flag;
+
+ HEVC_SublayerPTL sub_ptl[8];
+} HEVC_ProfileTierLevel;
+
+typedef struct
+{
+ u32 num_negative_pics;
+ u32 num_positive_pics;
+ s32 delta_poc[16];
+} HEVC_ReferencePictureSets;
+
+typedef struct
+{
+ s32 id, vps_id;
+ /*used to discard repeated SPSs - 0: not parsed, 1 parsed, 2 stored*/
+ u32 state;
+ u32 width, height;
+
+ HEVC_ProfileTierLevel ptl;
+
+ u8 chroma_format_idc;
+ Bool cw_flag ;
+ u32 cw_left, cw_right, cw_top, cw_bottom;
+ u8 bit_depth_luma;
+ u8 bit_depth_chroma;
+ u8 log2_max_pic_order_cnt_lsb;
+ Bool separate_colour_plane_flag;
+
+ u32 max_CU_width, max_CU_height, max_CU_depth;
+ u32 bitsSliceSegmentAddress;
+
+ u32 num_short_term_ref_pic_sets, num_long_term_ref_pic_sps;
+ HEVC_ReferencePictureSets rps[64];
+} HEVC_SPS;
+
+typedef struct
+{
+ s32 id;
+ u32 sps_id;
+ /*used to discard repeated SPSs - 0: not parsed, 1 parsed, 2 stored*/
+ u32 state;
+
+ Bool dependent_slice_segments_enabled_flag, tiles_enabled_flag, uniform_spacing_flag;
+ u32 num_extra_slice_header_bits;
+ Bool slice_segment_header_extension_present_flag, output_flag_present_flag;
+} HEVC_PPS;
+
+typedef struct
+{
+ u16 avg_bit_rate, max_bit_rate, avg_pic_rate;
+ u8 constand_pic_rate_idc;
+} HEVC_RateInfo;
+
+typedef struct
+{
+ s32 id;
+ /*used to discard repeated SPSs - 0: not parsed, 1 parsed, 2 stored*/
+ u32 state;
+ u8 max_sub_layer;
+ HEVC_ProfileTierLevel ptl;
+
+ HEVC_SublayerPTL sub_ptl[8];
+ HEVC_RateInfo rates[8];
+
+} HEVC_VPS;
+
+typedef struct
+{
+ AVCSeiRecoveryPoint recovery_point;
+ AVCSeiPicTiming pic_timing;
+
+} HEVC_SEI;
+
+typedef struct
+{
+ u8 nal_unit_type;
+ s8 temporal_id;
+
+ u32 frame_num, poc_lsb, slice_type;
+
+ s32 redundant_pic_cnt;
+
+ s32 poc;
+ u32 poc_msb, poc_msb_prev, poc_lsb_prev, frame_num_prev;
+ s32 frame_num_offset, frame_num_offset_prev;
+
+ HEVC_SPS *sps;
+ HEVC_PPS *pps;
+} HEVCSliceInfo;
+
+typedef struct
+{
+ HEVC_SPS sps[16]; /* range allowed in the spec is 0..15 */
+ s8 sps_active_idx; /*currently active sps; must be initalized to -1 in order to discard not yet decodable SEIs*/
+
+ HEVC_PPS pps[64];
+
+ HEVC_VPS vps[16];
+
+ HEVCSliceInfo s_info;
+ HEVC_SEI sei;
+
+ Bool is_svc;
+} HEVCState;
+
+enum
+{
+ GF_HEVC_TYPE_B = 0,
+ GF_HEVC_TYPE_P = 1,
+ GF_HEVC_TYPE_I = 2,
+};
+s32 gf_media_hevc_read_vps(char *data, u32 size, HEVCState *hevc);
+s32 gf_media_hevc_read_sps(char *data, u32 size, HEVCState *hevc);
+s32 gf_media_hevc_read_pps(char *data, u32 size, HEVCState *hevc);
+s32 gf_media_hevc_parse_nalu(GF_BitStream *bs, HEVCState *hevc, u8 *nal_unit_type, u8 *temporal_id);
+Bool gf_media_hevc_slice_is_intra(HEVCState *hevc);
+Bool gf_media_hevc_slice_is_IDR(HEVCState *hevc);
+
+
#endif /*GPAC_DISABLE_AV_PARSERS*/
typedef struct
diff --git a/include/gpac/internal/mpd.h b/include/gpac/internal/mpd.h
index dfee351..cbb6e42 100644
--- a/include/gpac/internal/mpd.h
+++ b/include/gpac/internal/mpd.h
@@ -94,7 +94,7 @@ typedef struct
#define GF_MPD_SEGMENT_BASE \
u32 timescale; \
u64 presentation_time_offset; \
- u32 index_range; \
+ GF_MPD_ByteRange *index_range; \
Bool index_range_exact; \
GF_MPD_URL *initialization_segment; \
GF_MPD_URL *representation_index; \
@@ -124,6 +124,7 @@ typedef struct
GF_MPD_ByteRange *media_range;
char *index;
GF_MPD_ByteRange *index_range;
+ u64 duration;
} GF_MPD_SegmentURL;
typedef struct
@@ -329,6 +330,7 @@ GF_MPD *gf_mpd_new();
void gf_mpd_del(GF_MPD *mpd);
/*frees a GF_MPD_SegmentURL structure (type-casted to void *)*/
void gf_mpd_segment_url_free(void *ptr);
+void gf_mpd_segment_base_free(void *ptr);
typedef struct _gf_file_get GF_FileDownload;
struct _gf_file_get
diff --git a/include/gpac/internal/smjs_api.h b/include/gpac/internal/smjs_api.h
index 756347b..f53bd16 100644
--- a/include/gpac/internal/smjs_api.h
+++ b/include/gpac/internal/smjs_api.h
@@ -52,6 +52,10 @@ typedef struct
/*new APIs*/
#if (JS_VERSION>=185)
+#ifdef USE_FFDEV_17
+#define USE_FFDEV_16
+#endif
+
#ifdef USE_FFDEV_16
#define USE_FFDEV_15
#endif
@@ -85,6 +89,24 @@ typedef double jsdouble;
#define JS_NewDouble(c, v) v
#define JS_PropertyStub_forSetter JS_StrictPropertyStub
+#if defined(USE_FFDEV_17)
+
+#define SMJS_DECL_FUNC_PROP_SET(func_name) JSBool func_name(JSContext *c, JSHandleObject __hobj, JSHandleId __hid, JSBool strict, JSMutableHandleValue __vp)
+#define SMJS_FUNC_PROP_SET(func_name) SMJS_DECL_FUNC_PROP_SET(func_name) { JSObject *obj = *(__hobj._); jsid id = *(__hid._); jsval *vp = __vp._;
+#define SMJS_FUNC_PROP_SET_NOVP(func_name) SMJS_DECL_FUNC_PROP_SET(func_name) { JSObject *obj = *(__hobj._); jsid id = *(__hid._);
+
+#define SMJS_DECL_FUNC_PROP_GET(func_name) JSBool func_name(JSContext *c, JSHandleObject __hobj, JSHandleId __hid, JSMutableHandleValue __vp)
+#define SMJS_FUNC_PROP_GET(func_name) SMJS_DECL_FUNC_PROP_GET( func_name ) { JSObject *obj = *(__hobj._); jsid id = *(__hid._); jsval *vp = __vp._;
+#define SMJS_CALL_PROP_STUB() JS_PropertyStub(c, __hobj, __hid, __vp)
+#define DECL_FINALIZE(func_name) void func_name(JSFreeOp *fop, JSObject *obj) { void *c = NULL;
+
+#define SMJS_FUNCTION_SPEC(__name, __fun, __argc) JS_FS(__name, __fun, __argc, 0)
+#define SMJS_PROPERTY_SPEC(__name, __tinyid, __flags, __getter, __setter) \
+ {__name, __tinyid, __flags, JSOP_WRAPPER(__getter), JSOP_WRAPPER(__setter)}
+
+
+#else
+
#ifdef USE_FFDEV_15
#define SMJS_DECL_FUNC_PROP_SET(func_name) JSBool func_name(JSContext *c, JSHandleObject __hobj, JSHandleId __hid, JSBool strict, jsval *vp)
@@ -105,8 +127,14 @@ typedef double jsdouble;
#endif
+#define SMJS_FUNC_PROP_SET_NOVP SMJS_FUNC_PROP_SET
#define SMJS_FUNCTION_SPEC(__name, __fun, __argc) {__name, __fun, __argc, 0}
+#define SMJS_PROPERTY_SPEC(__name, __tinyid, __flags, __getter, __setter) \
+ {__name, __tinyid, __flags, __getter, __setter}
+
+#endif
+
#define SMJS_FUNCTION(__name) __name(JSContext *c, uintN argc, jsval *argsvp)
#define SMJS_FUNCTION_EXT(__name, __ext) __name(JSContext *c, uintN argc, jsval *argsvp, __ext)
#define SMJS_ARGS jsval *argv = JS_ARGV(c, argsvp);
@@ -178,6 +206,7 @@ typedef double jsdouble;
#define SMJS_DECL_FUNC_PROP_SET(func_name) JSBool func_name(JSContext *c, JSObject *obj, jsval id, jsval *vp)
#define SMJS_FUNC_PROP_SET(func_name) SMJS_DECL_FUNC_PROP_SET(func_name) {
+#define SMJS_FUNC_PROP_SET_NOVP SMJS_FUNC_PROP_SET
#define SMJS_DECL_FUNC_PROP_GET(func_name) JSBool func_name(JSContext *c, JSObject *obj, jsval id, jsval *vp)
#define SMJS_FUNC_PROP_GET(func_name) SMJS_DECL_FUNC_PROP_GET( func_name) {
#define DECL_FINALIZE(func_name) void func_name(JSContext *c, JSObject *obj) {
@@ -187,6 +216,7 @@ typedef double jsdouble;
#define SMJS_PROP_GETTER jsval id
#define JS_PropertyStub_forSetter JS_PropertyStub
#define SMJS_FUNCTION_SPEC(__name, __fun, __argc) {__name, __fun, __argc, 0, 0}
+#define SMJS_PROPERTY_SPEC(__name, __tinyid, __flags, __getter, __setter) {__name, __tinyid, __flags, __getter, __setter}
#define SMJS_FUNCTION(__name) __name(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
#define SMJS_FUNCTION_EXT(__name, __ext) __name(JSContext *c, JSObject *obj, uintN argc, jsval *argv, jsval *rval, __ext)
#define SMJS_ARGS
diff --git a/include/gpac/isomedia.h b/include/gpac/isomedia.h
index 9c001f2..73aa5f5 100644
--- a/include/gpac/isomedia.h
+++ b/include/gpac/isomedia.h
@@ -179,7 +179,11 @@ enum
GF_AVCConfig to MPEG-4 ESD*/
GF_ISOM_SUBTYPE_AVC_H264 = GF_4CC( 'a', 'v', 'c', '1' ),
GF_ISOM_SUBTYPE_AVC2_H264 = GF_4CC( 'a', 'v', 'c', '2' ),
+ GF_ISOM_SUBTYPE_AVC3_H264 = GF_4CC( 'a', 'v', 'c', '3' ),
+ GF_ISOM_SUBTYPE_AVC4_H264 = GF_4CC( 'a', 'v', 'c', '4' ),
GF_ISOM_SUBTYPE_SVC_H264 = GF_4CC( 's', 'v', 'c', '1' ),
+ GF_ISOM_SUBTYPE_HVC1 = GF_4CC( 'h', 'v', 'c', '1' ),
+ GF_ISOM_SUBTYPE_HEV1 = GF_4CC( 'h', 'e', 'v', '1' ),
/*3GPP(2) extension subtypes*/
GF_ISOM_SUBTYPE_3GP_H263 = GF_4CC( 's', '2', '6', '3' ),
@@ -413,6 +417,9 @@ u32 gf_isom_get_track_id(GF_ISOFile *the_file, u32 trackNumber);
/*return the track number of the track of specified ID, or 0 if error*/
u32 gf_isom_get_track_by_id(GF_ISOFile *the_file, u32 trackID);
+/*return the original trackID of the track number n, or 0 if error*/
+u32 gf_isom_get_track_original_id(GF_ISOFile *movie, u32 trackNumber);
+
/*gets the enable flag of a track 0: NO, 1: yes, 2: error*/
u8 gf_isom_is_track_enabled(GF_ISOFile *the_file, u32 trackNumber);
@@ -625,8 +632,13 @@ return -1 if error, 0 if the reference is a NULL one, or the trackNumber
*/
GF_Err gf_isom_get_reference(GF_ISOFile *the_file, u32 trackNumber, u32 referenceType, u32 referenceIndex, u32 *refTrack);
-/*Return 1 if the given track has a reference to the given TreckID of a given ReferenceType, 0 otherwise*/
-Bool gf_isom_has_track_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 refTrackID);
+/*Return the referenced track ID for a track and a given ReferenceType and Index
+return -1 if error, 0 if the reference is a NULL one, or the trackNumber
+*/
+GF_Err gf_isom_get_reference_ID(GF_ISOFile *the_file, u32 trackNumber, u32 referenceType, u32 referenceIndex, u32 *refTrackID);
+
+/*Return referenceIndex if the given track has a reference to the given TreckID of a given ReferenceType, 0 otherwise*/
+u32 gf_isom_has_track_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 refTrackID);
u8 gf_isom_get_pl_indication(GF_ISOFile *the_file, u8 PL_Code);
@@ -794,6 +806,9 @@ GF_Err gf_isom_set_track_creation_time(GF_ISOFile *movie,u32 trackNumber, u64 ti
returns error if trackID is already in used in the file*/
GF_Err gf_isom_set_track_id(GF_ISOFile *the_file, u32 trackNumber, u32 trackID);
+/*force to rewrite all dependencies when trackID changes*/
+GF_Err gf_isom_rewrite_track_dependencies(GF_ISOFile *movie, u32 trackNumber);
+
/*Add samples to a track. Use streamDescriptionIndex to specify the desired stream (if several)*/
GF_Err gf_isom_add_sample(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample);
@@ -1556,6 +1571,9 @@ GF_AVCConfig *gf_isom_avc_config_get(GF_ISOFile *the_file, u32 trackNumber, u32
/*gets uncompressed SVC config - user is responsible for deleting it*/
GF_AVCConfig *gf_isom_svc_config_get(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex);
+/*gets uncompressed HEVC config - user is responsible for deleting it*/
+GF_HEVCConfig *gf_isom_hevc_config_get(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex);
+
typedef enum
{
GF_ISOM_AVCTYPE_NONE=0,
@@ -1563,8 +1581,27 @@ typedef enum
GF_ISOM_AVCTYPE_AVC_SVC,
GF_ISOM_AVCTYPE_SVC_ONLY,
} GF_ISOMAVCType;
+
u32 gf_isom_get_avc_svc_type(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex);
+
+enum
+{
+ /*all extractors are rewritten*/
+ GF_ISOM_NALU_EXTRACT_DEFAULT = 0,
+ /*all extractors are skipped but NALU data from this track is kept*/
+ GF_ISOM_NALU_EXTRACT_LAYER_ONLY,
+ /*all extractors are kept (untouched sample) - used for dumping modes*/
+ GF_ISOM_NALU_EXTRACT_INSPECT,
+ /*above mode is applied and PPS/SPS/... are appended in the front of every IDR*/
+ GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG = 1<<16,
+ /*above mode is applied and all start codes are rewritten*/
+ GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG = 2<<16,
+};
+
+GF_Err gf_isom_set_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber, u32 nalu_extract_mode);
+u32 gf_isom_get_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber);
+
#ifndef GPAC_DISABLE_ISOM_WRITE
/*creates new AVC config*/
GF_Err gf_isom_avc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AVCConfig *cfg, char *URLname, char *URNname, u32 *outDescriptionIndex);
@@ -1576,6 +1613,16 @@ GF_Err gf_isom_svc_config_update(GF_ISOFile *the_file, u32 trackNumber, u32 Desc
GF_Err gf_isom_svc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AVCConfig *cfg, char *URLname, char *URNname, u32 *outDescriptionIndex);
/*deletes SVC config*/
GF_Err gf_isom_svc_config_del(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex);
+
+/*sets avc3 entry type (inband SPS/PPS) instead of of avc1 (SPS/PPS in avcC box)*/
+GF_Err gf_isom_avc_set_inband_config(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex);
+
+
+/*creates new AVC config*/
+GF_Err gf_isom_hevc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_HEVCConfig *cfg, char *URLname, char *URNname, u32 *outDescriptionIndex);
+/*updates AVC config*/
+GF_Err gf_isom_hevc_config_update(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_HEVCConfig *cfg);
+
#endif /*GPAC_DISABLE_ISOM_WRITE*/
diff --git a/include/gpac/media_tools.h b/include/gpac/media_tools.h
index f860a7c..010f064 100644
--- a/include/gpac/media_tools.h
+++ b/include/gpac/media_tools.h
@@ -268,6 +268,7 @@ typedef struct
char *file_name;
char representationID[100];
char periodID[100];
+ char role[100];
u32 bandwidth;
} GF_DashSegmenterInput;
@@ -283,13 +284,24 @@ typedef enum
GF_DASH_PROFILE_UNKNOWN
} GF_DashProfile;
+
+typedef enum
+{
+ GF_DASH_BSMODE_NONE = 0,
+ GF_DASH_BSMODE_INBAND,
+ GF_DASH_BSMODE_MERGED,
+ GF_DASH_BSMODE_SINGLE,
+ GF_DASH_BSMODE_SINGLE_MERGED,
+
+} GF_DashSwitchingMode;
+
GF_Err gf_dasher_segment_files(const char *mpd_name, GF_DashSegmenterInput *inputs, u32 nb_inputs, GF_DashProfile profile,
const char *mpd_title, const char *mpd_source, const char *mpd_copyright,
const char *mpd_moreInfoURL, const char **mpd_base_urls, u32 nb_mpd_base_urls,
- Bool use_url_template, Bool single_segment, Bool single_file, Bool bitstream_switching_mode,
+ Bool use_url_template, Bool single_segment, Bool single_file, GF_DashSwitchingMode bitstream_switching_mode,
Bool segments_start_with_rap, Double dash_duration_sec, char *seg_rad_name, char *seg_ext,
Double frag_duration_sec, s32 subsegs_per_sidx, Bool daisy_chain_sidx, Bool fragments_start_with_rap, const char *tmp_dir,
- GF_Config *dash_ctx, Bool dash_dynamic, u32 mpd_update_time, u32 time_shift_depth, Double subduration);
+ GF_Config *dash_ctx, u32 dash_dynamic, u32 mpd_update_time, u32 time_shift_depth, Double subduration);
/*returns time to wait until end of currently generated segments*/
u32 gf_dasher_next_update_time(GF_Config *dash_ctx, u32 mpd_update_time);
@@ -339,6 +351,8 @@ enum
GF_EXPORT_USE_QCP = (1<<11),
/*indicates full NHML dump*/
GF_EXPORT_NHML_FULL = (1<<11),
+ /**/
+ GF_EXPORT_SVC_LAYER = (1<<12),
/*ony probes extraction format*/
GF_EXPORT_PROBE_ONLY = (1<<30),
/*when set by user during export, will abort*/
diff --git a/include/gpac/modules/service.h b/include/gpac/modules/service.h
index 388079f..e0b0575 100644
--- a/include/gpac/modules/service.h
+++ b/include/gpac/modules/service.h
@@ -94,6 +94,9 @@ typedef enum
GF_NET_SERVICE_INFO,
/*checks if there is an audio stream in the service - term->net only*/
GF_NET_SERVICE_HAS_AUDIO,
+
+ /*checks if there is a forced video size - if yes, info is stored in GF_NetComPixelAR - term->net only*/
+ GF_NET_SERVICE_HAS_FORCED_VIDEO_SIZE,
/*instructs the service to get the migration info - term->net only*/
GF_NET_SERVICE_MIGRATION_INFO,
diff --git a/include/gpac/mpeg4_odf.h b/include/gpac/mpeg4_odf.h
index a31acfb..4f05173 100644
--- a/include/gpac/mpeg4_odf.h
+++ b/include/gpac/mpeg4_odf.h
@@ -697,6 +697,9 @@ typedef struct
GF_List *IPIDataSet;
GF_List *IPMPDescriptorPointers;
GF_List *extensionDescriptors;
+
+ /* 1 if this stream is referenced by type GF_ISOM_REF_BASE, 0 otherwise*/
+ Bool has_ref_base;
} GF_ESD;
@@ -880,6 +883,36 @@ typedef struct
} GF_AVCConfig;
+
+/*used for SPS/PPS/VPS/SEI*/
+typedef struct
+{
+ u8 type;
+ u8 array_completeness;
+ GF_List *nalus;
+} GF_HEVCParamArray;
+
+
+typedef struct
+{
+ u8 configurationVersion;
+ u8 profile_space;
+ u8 profile_idc;
+ u8 constraint_indicator_flags;
+ u8 level_idc;
+ u32 profile_compatibility_indications;
+ u8 chromaFormat;
+ u8 luma_bit_depth;
+ u8 chroma_bit_depth;
+ u16 avgFrameRate;
+ u8 constantFrameRate;
+ u8 numTemporalLayers;
+
+ u8 nal_unit_size;
+
+ GF_List *param_array;
+} GF_HEVCConfig;
+
/************************************************************
Media Control Extensions
************************************************************/
@@ -1073,6 +1106,14 @@ GF_AVCConfig *gf_odf_avc_cfg_read(char *dsi, u32 dsi_size);
/*writes GF_AVCConfig as MPEG-4 DSI*/
GF_Err gf_odf_avc_cfg_write(GF_AVCConfig *cfg, char **outData, u32 *outSize);
+
+GF_HEVCConfig *gf_odf_hevc_cfg_new();
+void gf_odf_hevc_cfg_del(GF_HEVCConfig *cfg);
+GF_Err gf_odf_hevc_cfg_write_bs(GF_HEVCConfig *cfg, GF_BitStream *bs);
+GF_Err gf_odf_hevc_cfg_write(GF_HEVCConfig *cfg, char **outData, u32 *outSize);
+GF_HEVCConfig *gf_odf_hevc_cfg_read_bs(GF_BitStream *bs);
+GF_HEVCConfig *gf_odf_hevc_cfg_read(char *dsi, u32 dsi_size);
+
/*destroy the descriptors in a list but not the list*/
GF_Err gf_odf_desc_list_del(GF_List *descList);
diff --git a/include/gpac/mpegts.h b/include/gpac/mpegts.h
index 6bf26ac..f4ef599 100644
--- a/include/gpac/mpegts.h
+++ b/include/gpac/mpegts.h
@@ -206,6 +206,7 @@ enum
GF_M2TS_SYSTEMS_MPEG4_SECTIONS = 0x13,
GF_M2TS_VIDEO_H264 = 0x1B,
+ GF_M2TS_VIDEO_HEVC = 0x24,
GF_M2TS_AUDIO_AC3 = 0x81,
GF_M2TS_AUDIO_DTS = 0x8A,
@@ -758,6 +759,8 @@ struct tag_m2ts_demux
u32 stb_at_last_pcr;
u32 nb_pck;
Bool loop_demux;
+ const char *ts_data_chunk;
+ u32 ts_data_chunk_size;
/* "Network" = "MobileIP", "DefaultMCastInterface" */
Bool MobileIPEnabled;
diff --git a/include/gpac/setup.h b/include/gpac/setup.h
index cbf8d09..59e2d87 100644
--- a/include/gpac/setup.h
+++ b/include/gpac/setup.h
@@ -425,6 +425,11 @@ void gf_memory_print(void); /*prints the state of current allocations*/
/*safety checks on macros*/
+#ifdef GPAC_DISABLE_ZLIB
+# define GPAC_DISABLE_LOADER_BT
+# define GPAC_DISABLE_SWF_IMPORT
+#endif
+
#ifdef GPAC_DISABLE_VRML
# ifndef GPAC_DISABLE_BIFS
# define GPAC_DISABLE_BIFS
diff --git a/include/gpac/tools.h b/include/gpac/tools.h
index bd99679..fa08ffc 100644
--- a/include/gpac/tools.h
+++ b/include/gpac/tools.h
@@ -690,7 +690,7 @@ GF_Err gf_cleanup_dir(char* DirPathName);
* \param size buffer size
* \return computed CRC32
*/
-u32 gf_crc_32(char *data, u32 size);
+u32 gf_crc_32(const char *data, u32 size);
/*!\brief run-time system info object
diff --git a/modules/ffmpeg_in/ffmpeg_decode.c b/modules/ffmpeg_in/ffmpeg_decode.c
index 592cee2..af5efe4 100644
--- a/modules/ffmpeg_in/ffmpeg_decode.c
+++ b/modules/ffmpeg_in/ffmpeg_decode.c
@@ -696,88 +696,104 @@ redecode:
w = ctx->width;
h = ctx->height;
- if (ffd->check_h264_isma) {
- /*for AVC bitstreams after ISMA decryption, in case (as we do) the decryption DRM tool
- doesn't put back nalu size, do it ourselves...*/
- if (inBuffer && !inBuffer[0] && !inBuffer[1] && !inBuffer[2] && (inBuffer[3]==0x01)) {
- u32 nalu_size;
- char *start, *end, *bufferEnd;
-
- start = inBuffer;
- end = inBuffer + 4;
- bufferEnd = inBuffer + inBufferLength;
- /* FIXME : SOUCHAY : not sure of exact behaviour, but old one was reading non-allocated memory */
- while ((end+3) < bufferEnd) {
- if (!end[0] && !end[1] && !end[2] && (end[3]==0x01)) {
- nalu_size = end - start - 4;
- start[0] = (nalu_size>>24)&0xFF;
- start[1] = (nalu_size>>16)&0xFF;
- start[2] = (nalu_size>>8)&0xFF;
- start[3] = (nalu_size)&0xFF;
- start = end;
- end = start+4;
- continue;
+ /*we have a valid frame not yet dispatched*/
+ if (ffd->had_pic) {
+ ffd->had_pic = 0;
+ gotpic = 1;
+ } else {
+ if (ffd->check_h264_isma) {
+ /*for AVC bitstreams after ISMA decryption, in case (as we do) the decryption DRM tool
+ doesn't put back nalu size, do it ourselves...*/
+ if (inBuffer && !inBuffer[0] && !inBuffer[1] && !inBuffer[2] && (inBuffer[3]==0x01)) {
+ u32 nalu_size;
+ char *start, *end, *bufferEnd;
+
+ start = inBuffer;
+ end = inBuffer + 4;
+ bufferEnd = inBuffer + inBufferLength;
+ /* FIXME : SOUCHAY : not sure of exact behaviour, but old one was reading non-allocated memory */
+ while ((end+3) < bufferEnd) {
+ if (!end[0] && !end[1] && !end[2] && (end[3]==0x01)) {
+ nalu_size = end - start - 4;
+ start[0] = (nalu_size>>24)&0xFF;
+ start[1] = (nalu_size>>16)&0xFF;
+ start[2] = (nalu_size>>8)&0xFF;
+ start[3] = (nalu_size)&0xFF;
+ start = end;
+ end = start+4;
+ continue;
+ }
+ end++;
}
- end++;
+ nalu_size = (inBuffer+inBufferLength) - start - 4;
+ start[0] = (nalu_size>>24)&0xFF;
+ start[1] = (nalu_size>>16)&0xFF;
+ start[2] = (nalu_size>>8)&0xFF;
+ start[3] = (nalu_size)&0xFF;
+ ffd->check_h264_isma = 2;
+ }
+ /*if we had ISMA E&A and lost it this is likely due to a pck loss - do NOT switch back to regular*/
+ else if (ffd->check_h264_isma == 1) {
+ ffd->check_h264_isma = 0;
}
- nalu_size = (inBuffer+inBufferLength) - start - 4;
- start[0] = (nalu_size>>24)&0xFF;
- start[1] = (nalu_size>>16)&0xFF;
- start[2] = (nalu_size>>8)&0xFF;
- start[3] = (nalu_size)&0xFF;
- ffd->check_h264_isma = 2;
- }
- /*if we had ISMA E&A and lost it this is likely due to a pck loss - do NOT switch back to regular*/
- else if (ffd->check_h264_isma == 1) {
- ffd->check_h264_isma = 0;
}
- }
-#ifdef USE_AVCODEC2
- if (avcodec_decode_video2(ctx, frame, &gotpic, &pkt) < 0) {
-#else
- if (avcodec_decode_video(ctx, frame, &gotpic, inBuffer, inBufferLength) < 0) {
-#endif
- if (!ffd->check_short_header) {
- return GF_NON_COMPLIANT_BITSTREAM;
- }
+ #ifdef USE_AVCODEC2
+ if (avcodec_decode_video2(ctx, frame, &gotpic, &pkt) < 0) {
+ #else
+ if (avcodec_decode_video(ctx, frame, &gotpic, inBuffer, inBufferLength) < 0) {
+ #endif
+ if (!ffd->check_short_header) {
+ return GF_NON_COMPLIANT_BITSTREAM;
+ }
- /*switch to H263 (ffmpeg MPEG-4 codec doesn't understand short headers)*/
- {
- u32 old_codec = (*codec)->id;
- ffd->check_short_header = 0;
- /*OK we loose the DSI stored in the codec context, but H263 doesn't need any, and if we're
- here this means the DSI was broken, so no big deal*/
- avcodec_close(ctx);
- *codec = avcodec_find_decoder(CODEC_ID_H263);
- if (! (*codec) || (avcodec_open(ctx, *codec)<0)) return GF_NON_COMPLIANT_BITSTREAM;
-#if USE_AVCODEC2
- if (avcodec_decode_video2(ctx, frame, &gotpic, &pkt) < 0) {
-#else
- if (avcodec_decode_video(ctx, frame, &gotpic, inBuffer, inBufferLength) < 0) {
-#endif
- /*nope, stay in MPEG-4*/
+ /*switch to H263 (ffmpeg MPEG-4 codec doesn't understand short headers)*/
+ {
+ u32 old_codec = (*codec)->id;
+ ffd->check_short_header = 0;
+ /*OK we loose the DSI stored in the codec context, but H263 doesn't need any, and if we're
+ here this means the DSI was broken, so no big deal*/
avcodec_close(ctx);
- *codec = avcodec_find_decoder(old_codec);
- assert(*codec);
- avcodec_open(ctx, *codec);
- return GF_NON_COMPLIANT_BITSTREAM;
+ *codec = avcodec_find_decoder(CODEC_ID_H263);
+ if (! (*codec) || (avcodec_open(ctx, *codec)<0)) return GF_NON_COMPLIANT_BITSTREAM;
+ #if USE_AVCODEC2
+ if (avcodec_decode_video2(ctx, frame, &gotpic, &pkt) < 0) {
+ #else
+ if (avcodec_decode_video(ctx, frame, &gotpic, inBuffer, inBufferLength) < 0) {
+ #endif
+ /*nope, stay in MPEG-4*/
+ avcodec_close(ctx);
+ *codec = avcodec_find_decoder(old_codec);
+ assert(*codec);
+ avcodec_open(ctx, *codec);
+ return GF_NON_COMPLIANT_BITSTREAM;
+ }
}
}
- }
- if (!gotpic && (!ctx->width || !ctx->height) ) {
- ctx->width = w;
- ctx->height = h;
- return GF_OK;
+ /*
+ if (!gotpic && (!ctx->width || !ctx->height) ) {
+ ctx->width = w;
+ ctx->height = h;
+ return GF_OK;
+ }
+ */
+ /*some streams use odd width/height frame values*/
+ if (ffd->out_pix_fmt == GF_PIXEL_YV12) {
+ if (ctx->width%2) ctx->width++;
+ if (ctx->height%2) ctx->height++;
+ }
}
- /*some streams use odd width/height frame values*/
- if (ffd->out_pix_fmt == GF_PIXEL_YV12) {
- if (ctx->width%2) ctx->width++;
- if (ctx->height%2) ctx->height++;
+ /*we have a picture and need resize, do it*/
+ if (gotpic && ffd->needs_output_resize) {
+ ffd->needs_output_resize=0;
+ ffd->had_pic = 1;
+ *outBufferLength = ffd->out_size;
+ return GF_BUFFER_TOO_SMALL;
}
+
/*recompute outsize in case on-the-fly change*/
if ((w != ctx->width) || (h != ctx->height)) {
outsize = ctx->width * ctx->height * 3;
@@ -787,6 +803,17 @@ redecode:
ffd->yuv_size = 3 * ctx->width * ctx->height / 2;
}
ffd->out_size = outsize;
+
+ if (!ffd->no_par_update && ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) {
+ ffd->previous_par = (ctx->sample_aspect_ratio.num<<16) | ctx->sample_aspect_ratio.den;
+ }
+
+ /*we didn't get any picture: wait for a picture before resizing output buffer, otherwise we will have no
+ video in the output buffer*/
+ if (!gotpic) {
+ ffd->needs_output_resize = 1;
+ return GF_OK;
+ }
*outBufferLength = ffd->out_size;
if (ffd->check_h264_isma) {
inBuffer[0] = inBuffer[1] = inBuffer[2] = 0;
@@ -798,17 +825,21 @@ redecode:
*cached_sws = NULL;
}
#endif
- if (!ffd->no_par_update && ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) {
- ffd->previous_par = (ctx->sample_aspect_ratio.num<<16) | ctx->sample_aspect_ratio.den;
- }
+ ffd->had_pic = 1;
return GF_BUFFER_TOO_SMALL;
}
/*check PAR in case on-the-fly change*/
if (!ffd->no_par_update && ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) {
u32 new_par = (ctx->sample_aspect_ratio.num<<16) | ctx->sample_aspect_ratio.den;
- if (new_par != ffd->previous_par) {
+ if (ffd->previous_par && (new_par != ffd->previous_par)) {
ffd->previous_par = new_par;
+
+ if (!gotpic) {
+ ffd->needs_output_resize = 1;
+ return GF_OK;
+ }
*outBufferLength = ffd->out_size;
+ ffd->had_pic = 1;
return GF_BUFFER_TOO_SMALL;
}
}
@@ -955,6 +986,9 @@ static u32 FFDEC_CanHandleStream(GF_BaseDecoder *plug, u32 StreamType, GF_ESD *e
GF_AVCConfig *cfg = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
if (!cfg) return GF_CODEC_SUPPORTED;
+ if (esd->has_ref_base)
+ is_svc = 1;
+
/*decode all NALUs*/
count = gf_list_count(cfg->sequenceParameterSets);
for (i=0; i
-#ifndef FREENECT_RESOLUTION_HIGH
-//#define FREENECT_MINIMAL
+#if !defined(FREENECT_DEVICE_CAMERA) && defined(FREENECT_FRAME_W)
+#define FREENECT_MINIMAL
#endif
diff --git a/modules/gpac_js/gpac_js.c b/modules/gpac_js/gpac_js.c
index 2144838..4004f48 100644
--- a/modules/gpac_js/gpac_js.c
+++ b/modules/gpac_js/gpac_js.c
@@ -849,21 +849,21 @@ static void gjs_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene, JSContext
GF_JSAPIParam par;
JSPropertySpec gpacEvtClassProps[] = {
- {"type", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"keycode", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"mouse_x", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"mouse_y", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"picked", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"wheel", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"button", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("type", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("keycode", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("mouse_x", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("mouse_y", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("picked", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("wheel", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("button", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec gpacEvtClassFuncs[] = {
SMJS_FUNCTION_SPEC(0, 0, 0)
};
JSPropertySpec gpacClassProps[] = {
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec gpacClassFuncs[] = {
SMJS_FUNCTION_SPEC("getOption", gpac_getOption, 3),
@@ -906,7 +906,6 @@ static void gjs_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene, JSContext
if (!scene) return;
-
JS_SETUP_CLASS(gjs->gpacClass, "GPAC", JSCLASS_HAS_PRIVATE, gpac_getProperty, gpac_setProperty, JS_FinalizeStub);
if (!gjs->gpac_obj) {
diff --git a/modules/isom_in/isom_in.h b/modules/isom_in/isom_in.h
index 18945a1..226722c 100644
--- a/modules/isom_in/isom_in.h
+++ b/modules/isom_in/isom_in.h
@@ -69,12 +69,15 @@ typedef struct
typedef struct
{
- u32 track;
+ u32 track, track_id;
+ /*base track if scalable media, 0 otherwise*/
+ u32 base_track;
+ u32 next_track;
LPNETCHANNEL channel;
ISOMReader *owner;
u64 duration;
- Bool wait_for_segment_switch, needs_codec_update;
+ Bool wait_for_segment_switch;
/*current sample*/
GF_ISOSample *sample;
GF_SLHeader current_slh;
diff --git a/modules/isom_in/load.c b/modules/isom_in/load.c
index 02405ab..8fe8a9d 100644
--- a/modules/isom_in/load.c
+++ b/modules/isom_in/load.c
@@ -86,7 +86,7 @@ void isor_declare_objects(ISOMReader *read)
GF_ObjectDescriptor *od;
GF_ESD *esd;
const char *tag;
- u32 i, count, ocr_es_id, tlen;
+ u32 i, count, ocr_es_id, tlen, base_track, j, track_id;
ocr_es_id = 0;
@@ -106,8 +106,28 @@ void isor_declare_objects(ISOMReader *read)
default:
continue;
}
+
+ /*we declare only the base track (i.e base_track == 0)*/
+ gf_isom_get_reference(read->mov, i+1, GF_ISOM_REF_BASE, 1, &base_track);
+ if (base_track)
+ continue;
esd = gf_media_map_esd(read->mov, i+1);
if (esd) {
+ esd->has_ref_base = 0;
+ track_id = gf_isom_get_track_id(read->mov, i+1);
+ for (j = 0; j < count; j++)
+ {
+ if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_BASE, track_id))
+ {
+ esd->has_ref_base = 1;
+ break;
+ }
+ if (gf_isom_get_avc_svc_type(read->mov, j+1, 1)>=GF_ISOM_AVCTYPE_AVC_SVC) {
+ esd->has_ref_base = 1;
+ break;
+ }
+ }
+
od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
od->service_ifce = read->input;
od->objectDescriptorID = 0;
diff --git a/modules/isom_in/read.c b/modules/isom_in/read.c
index 24c688a..b737263 100644
--- a/modules/isom_in/read.c
+++ b/modules/isom_in/read.c
@@ -56,6 +56,7 @@ static void isor_delete_channel(ISOMReader *reader, ISOMChannel *ch)
static GFINLINE Bool isor_is_local(const char *url)
{
if (!strnicmp(url, "file://", 7)) return 1;
+ if (!strnicmp(url, "gmem://", 7)) return 1;
if (strstr(url, "://")) return 0;
/*the rest is local (mounted on FS)*/
return 1;
@@ -497,7 +498,7 @@ static GF_Descriptor *ISOR_GetServiceDesc(GF_InputService *plug, u32 expect_type
GF_Err ISOR_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const char *url, Bool upstream)
{
- u32 ESID;
+ u32 ESID, base_track, count, i;
ISOMChannel *ch;
GF_NetworkCommand com;
u32 track;
@@ -561,6 +562,7 @@ GF_Err ISOR_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const ch
ch->channel = channel;
gf_list_add(read->channels, ch);
ch->track = track;
+ ch->track_id = gf_isom_get_track_id(read->mov, ch->track);
switch (gf_isom_get_media_type(ch->owner->mov, ch->track)) {
case GF_ISOM_MEDIA_OCR:
ch->streamType = GF_STREAM_OCR;
@@ -568,6 +570,27 @@ GF_Err ISOR_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const ch
case GF_ISOM_MEDIA_SCENE:
ch->streamType = GF_STREAM_SCENE;
break;
+ case GF_ISOM_MEDIA_VISUAL:
+ count = gf_isom_get_track_count(ch->owner->mov);
+ base_track = 0;
+ for (i = 0; i < count; i++)
+ {
+ gf_isom_get_reference(ch->owner->mov, i+1, GF_ISOM_REF_BASE, 1, &base_track);
+ if (base_track)
+ break;
+ }
+ ch->base_track = base_track;
+ ch->next_track = 0;
+
+ /*set track to last layer (hopefully max quality)*/
+ for (i = 0; i < count; i++) {
+ gf_isom_get_reference(ch->owner->mov, i+1, GF_ISOM_REF_BASE, 1, &base_track);
+ if (base_track==ch->base_track)
+ ch->track = i+1;
+ }
+ /*in scalable mode add SPS/PPS in-band*/
+ gf_isom_set_nalu_extract_mode(ch->owner->mov, ch->track, GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG);
+ break;
}
ch->has_edit_list = gf_isom_get_edit_segment_count(ch->owner->mov, ch->track) ? 1 : 0;
@@ -698,11 +721,64 @@ static u64 check_round(ISOMChannel *ch, u64 val_ts, Double val_range, Bool make_
return val_ts;
}
+/*switch channel quality. Return next channel or current channel if error*/
+static
+u32 gf_channel_switch_quality(ISOMChannel *ch, GF_ISOFile *the_file, Bool switch_up)
+{
+ u32 i, count, next_track, trackID, cur_track;
+ s32 ref_count;
+
+ cur_track = ch->next_track ? ch->next_track : ch->track;
+ count = gf_isom_get_track_count(the_file);
+ trackID = gf_isom_get_track_id(the_file, cur_track);
+ next_track = 0;
+
+ if (switch_up)
+ {
+ for (i = 0; i < count; i++)
+ {
+ ref_count = gf_isom_get_reference_count(the_file, i+1, GF_ISOM_REF_SCAL);
+ if (ref_count < 0)
+ return cur_track; //error
+ else if (ref_count == 0)
+ continue;
+ /*next track is the one that has the last reference of type GF_ISOM_REF_SCAL refers to this current track*/
+ else if ((u32)ref_count == gf_isom_has_track_reference(the_file, i+1, GF_ISOM_REF_SCAL, trackID))
+ {
+ next_track = i+1;
+ break;
+ }
+ }
+ /*this is the highest quality*/
+ if (!next_track)
+ return cur_track;
+ }
+ else
+ {
+ if (cur_track == ch->base_track)
+ return cur_track;
+ ref_count = gf_isom_get_reference_count(the_file, cur_track, GF_ISOM_REF_SCAL);
+ if (ref_count < 0)
+ return cur_track;
+ gf_isom_get_reference(the_file, cur_track, GF_ISOM_REF_SCAL, ref_count, &next_track);
+ if (!next_track)
+ return cur_track;
+ }
+
+ /*in scalable mode add SPS/PPS in-band*/
+ gf_isom_set_nalu_extract_mode(the_file, next_track, GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG);
+
+ return next_track;
+}
+
+
GF_Err ISOR_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
{
Double track_dur, media_dur;
ISOMChannel *ch;
ISOMReader *read;
+ u32 count, i;
+
if (!plug || !plug->priv || !com) return GF_SERVICE_ERROR;
read = (ISOMReader *) plug->priv;
@@ -735,6 +811,20 @@ GF_Err ISOR_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
}
return GF_NOT_SUPPORTED;
}
+
+ if (com->command_type == GF_NET_SERVICE_QUALITY_SWITCH)
+ {
+ count = gf_list_count(read->channels);
+ for (i = 0; i < count; i++)
+ {
+ ch = (ISOMChannel *)gf_list_get(read->channels, i);
+ if (ch->base_track) {
+ ch->next_track = gf_channel_switch_quality(ch, read->mov, com->switch_quality.up);
+ }
+ }
+ return GF_OK;
+ }
+
if (!com->base.on_channel) return GF_NOT_SUPPORTED;
ch = isor_get_channel(read, com->base.on_channel);
@@ -818,9 +908,9 @@ GF_Err ISOR_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
}
gf_odf_desc_del((GF_Descriptor *) dcd);
}
- }
return GF_OK;
}
+ }
return GF_NOT_SUPPORTED;
}
diff --git a/modules/isom_in/read_ch.c b/modules/isom_in/read_ch.c
index 744a69d..841b3e9 100644
--- a/modules/isom_in/read_ch.c
+++ b/modules/isom_in/read_ch.c
@@ -98,9 +98,24 @@ static void check_segment_switch(ISOMReader *read)
ch->wait_for_segment_switch = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Track %d - cur sample %d - new sample count %d\n", ch->track, ch->sample_num, gf_isom_get_sample_count(ch->owner->mov, ch->track) ));
if (param.url_query.next_url_init_or_switch_segment) {
- ch->needs_codec_update = 1;
+ ch->track = gf_isom_get_track_by_id(read->mov, ch->track_id);
+ if (!ch->track) {
+ if (gf_isom_get_track_count(read->mov)==1) {
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Mismatch between track IDs of different representations\n"));
+ ch->track = 1;
+ } else {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[IsoMedia] Mismatch between track IDs of different representations\n"));
+ }
+ }
+
+ /*rewrite all upcoming SPS/PPS into the samples*/
+ gf_isom_set_nalu_extract_mode(read->mov, ch->track, GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG);
+
/*we changed our moov structure, sample_num now starts from 0*/
ch->sample_num = 0;
+ } else {
+ /*no need to rewrite upcoming SPS/PPS into the samples*/
+ gf_isom_set_nalu_extract_mode(read->mov, ch->track, GF_ISOM_NALU_EXTRACT_DEFAULT);
}
}
} else {
@@ -259,6 +274,12 @@ fetch_next:
ch->sample_num++;
goto fetch_next;
}
+ if (ch->sample && ch->sample->IsRAP && ch->next_track) {
+ ch->track = ch->next_track;
+ ch->next_track = 0;
+ gf_isom_sample_del(&ch->sample);
+ goto fetch_next;
+ }
}
if (!ch->sample) {
/*incomplete file - check if we're still downloading or not*/
@@ -325,62 +346,6 @@ fetch_next:
ch->current_slh.isma_encrypted = 0;
}
}
-
- /*this is ugly we need a rearchitecture of the streaming part of GPAC to handle codec changes properly - fortunately in DASH we cannot switch codec on
- the fly (not in the same representation)!! */
- if (ch->sample && ch->needs_codec_update) {
- GF_AVCConfig *avccfg, *svccfg;
- GF_AVCConfigSlot *slc;
- GF_BitStream *bs;
- u32 i;
- ch->needs_codec_update = 0;
-
- GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Codec configuration changed - rewriting sample\n"));
-
- switch (gf_isom_get_media_subtype(ch->owner->mov, ch->track, 1)) {
- case GF_ISOM_SUBTYPE_AVC_H264:
- case GF_ISOM_SUBTYPE_AVC2_H264:
- case GF_ISOM_SUBTYPE_SVC_H264:
- avccfg = gf_isom_avc_config_get(ch->owner->mov, ch->track, 1);
- svccfg = gf_isom_svc_config_get(ch->owner->mov, ch->track, 1);
-
- bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
- if (avccfg) {
- for (i=0; isequenceParameterSets); i++) {
- slc = gf_list_get(avccfg->sequenceParameterSets, i);
- gf_bs_write_int(bs, slc->size, avccfg->nal_unit_size*8);
- gf_bs_write_data(bs, slc->data, slc->size);
- }
- for (i=0; ipictureParameterSets); i++) {
- slc = gf_list_get(avccfg->pictureParameterSets, i);
- gf_bs_write_int(bs, slc->size, avccfg->nal_unit_size*8);
- gf_bs_write_data(bs, slc->data, slc->size);
- }
- gf_odf_avc_cfg_del(avccfg);
- }
- if (svccfg) {
- for (i=0; isequenceParameterSets); i++) {
- slc = gf_list_get(svccfg->sequenceParameterSets, i);
- gf_bs_write_int(bs, slc->size, avccfg->nal_unit_size*8);
- gf_bs_write_data(bs, slc->data, slc->size);
- }
- for (i=0; ipictureParameterSets); i++) {
- slc = gf_list_get(svccfg->pictureParameterSets, i);
- gf_bs_write_int(bs, slc->size, avccfg->nal_unit_size*8);
- gf_bs_write_data(bs, slc->data, slc->size);
- }
- gf_odf_avc_cfg_del(svccfg);
- }
- gf_bs_write_data(bs, ch->sample->data, ch->sample->dataLength);
- gf_free(ch->sample->data);
- ch->sample->data = 0;
- gf_bs_get_content(bs, &ch->sample->data, &ch->sample->dataLength);
- gf_bs_del(bs);
- break;
- default:
- break;
- }
- }
}
void isor_reader_release_sample(ISOMChannel *ch)
diff --git a/modules/mp3_in/mp3_in.c b/modules/mp3_in/mp3_in.c
index 4269701..5db68c0 100644
--- a/modules/mp3_in/mp3_in.c
+++ b/modules/mp3_in/mp3_in.c
@@ -131,13 +131,35 @@ static void mp3_setup_object(MP3Reader *read)
}
}
-
-static Bool MP3_ConfigureFromFile(MP3Reader *read)
+/**
+ * Returns TRUE if file is ready to be read, FALSE otherwise
+ * @param read Reader
+ * @param minSizeToRead How much bytes do we need to start reading at minimum
+ */
+static Bool MP3_ConfigureFromFile(MP3Reader *read, u32 *minSizeToRead)
{
+ unsigned char id3v2[10];
u32 hdr, size;
u64 pos;
if (!read->stream) return 0;
-
+ /* ID3VVFFFFSIZE = 13bytes
+ * ID3 string
+ * VV = Version
+ * F = Flags
+ * SIZE = 32bits size with first Most Significant bit set to 0 -> 28 bits
+ * Size starts AFTER this header, meaning we have to add 10 bytes
+ */
+ pos = fread(id3v2, sizeof(unsigned char), 10, read->stream);
+ *minSizeToRead = 0;
+ if (pos == 10){
+ /* Did we read an ID3v2 ? */
+ if (id3v2[0] == 'I' && id3v2[1] == 'D' && id3v2[2] == '3'){
+ int sz = 10 + ((id3v2[9] & 0x7f) + ((id3v2[8] & 0x7f) << 7) + ((id3v2[7] & 0x7f) << 14) + ((id3v2[6] & 0x7f) << 21));
+ //printf("Size of id3v2 header = %d\n", sz);
+ *minSizeToRead = sz;
+ }
+ }
+ gf_f64_seek(read->stream, 0, SEEK_SET);
hdr = gf_mp3_get_next_header(read->stream);
if (!hdr) return 0;
read->sample_rate = gf_mp3_sampling_rate(hdr);
@@ -318,14 +340,15 @@ void MP3_NetIO(void *cbk, GF_NETIO_Parameter *param)
read->stream = gf_f64_open((char *) szCache, "rb");
if (!read->stream) e = GF_SERVICE_ERROR;
else {
+ u32 minSizeToRead = 0;
/*if full file at once (in cache) parse duration*/
if (e==GF_EOS) read->is_remote = 0;
e = GF_OK;
/*not enough data*/
- if (!MP3_ConfigureFromFile(read)) {
+ if (!MP3_ConfigureFromFile(read, &minSizeToRead)) {
gf_dm_sess_get_stats(read->dnload, NULL, NULL, NULL, &bytes_done, NULL, NULL);
/*bad data - there's likely some ID3 around...*/
- if (bytes_done>100*1024) {
+ if (bytes_done>(100*1024 + minSizeToRead)) {
e = GF_CORRUPTED_DATA;
} else {
fclose(read->stream);
@@ -366,6 +389,7 @@ void mp3_download_file(GF_InputService *plug, char *url)
static GF_Err MP3_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url)
{
char szURL[2048];
+ u32 minSizeToRead = 0;
char *ext;
GF_Err reply;
MP3Reader *read = plug->priv;
@@ -389,7 +413,7 @@ static GF_Err MP3_ConnectService(GF_InputService *plug, GF_ClientService *serv,
read->stream = gf_f64_open(szURL, "rb");
if (!read->stream) {
reply = GF_URL_ERROR;
- } else if (!MP3_ConfigureFromFile(read)) {
+ } else if (!MP3_ConfigureFromFile(read, &minSizeToRead)) {
fclose(read->stream);
read->stream = NULL;
reply = GF_NOT_SUPPORTED;
@@ -532,7 +556,8 @@ static GF_Err MP3_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
read->done = 0;
/*PLAY after complete download, estimate duration*/
if (!read->is_remote && !read->duration) {
- MP3_ConfigureFromFile(read);
+ u32 minSizeToRead = 0;
+ MP3_ConfigureFromFile(read, &minSizeToRead);
if (read->duration) {
GF_NetworkCommand rcfg;
rcfg.base.on_channel = read->ch;
diff --git a/modules/mpd_in/mpd_in.c b/modules/mpd_in/mpd_in.c
index 7c4bbe9..689092c 100644
--- a/modules/mpd_in/mpd_in.c
+++ b/modules/mpd_in/mpd_in.c
@@ -44,7 +44,11 @@ typedef struct __mpd_module
Bool connection_ack_sent;
Bool in_seek;
+ Bool memory_storage;
+ Bool use_max_res, immediate_switch;
Double previous_start_range;
+ /*max width & height in all active representations*/
+ u32 width, height;
} GF_MPD_In;
typedef struct
@@ -165,12 +169,12 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param)
gf_dash_request_period_switch(mpdin->dash);
break;
}
- gf_sleep(20);
+ gf_sleep(30);
}
}
return GF_EOS;
}
- gf_sleep(16);
+ gf_sleep(30);
}
nb_segments_cached = gf_dash_group_get_num_segments_ready(mpdin->dash, group_idx, &group_done);
@@ -186,7 +190,7 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param)
}
gf_dash_group_get_next_segment_location(mpdin->dash, group_idx, ¶m->url_query.next_url, ¶m->url_query.start_range, ¶m->url_query.end_range,
- ¶m->url_query.next_url_init_or_switch_segment, ¶m->url_query.switch_start_range , ¶m->url_query.switch_end_range,
+ NULL, ¶m->url_query.next_url_init_or_switch_segment, ¶m->url_query.switch_start_range , ¶m->url_query.switch_end_range,
&src_url);
{
@@ -313,9 +317,11 @@ void mpdin_dash_io_delete_cache_file(GF_DASHFileIO *dashio, GF_DASHFileIOSession
GF_DASHFileIOSession mpdin_dash_io_create(GF_DASHFileIO *dashio, Bool persistent, const char *url)
{
+ GF_DownloadSession *sess;
u32 flags = GF_NETIO_SESSION_NOT_THREADED;
GF_MPD_In *mpdin = (GF_MPD_In *)dashio->udta;
- GF_DownloadSession *sess;
+ if (mpdin->memory_storage)
+ flags |= GF_NETIO_SESSION_MEMORY_CACHE;
if (persistent) flags |= GF_NETIO_SESSION_PERSISTENT;
sess = gf_term_download_new(mpdin->service, url, flags, NULL, NULL);
@@ -333,9 +339,9 @@ GF_Err mpdin_dash_io_setup_from_url(GF_DASHFileIO *dashio, GF_DASHFileIOSession
{
return gf_dm_sess_setup_from_url((GF_DownloadSession *)session, url);
}
-GF_Err mpdin_dash_io_set_range(GF_DASHFileIO *dashio, GF_DASHFileIOSession session, u64 start_range, u64 end_range)
+GF_Err mpdin_dash_io_set_range(GF_DASHFileIO *dashio, GF_DASHFileIOSession session, u64 start_range, u64 end_range, Bool discontinue_cache)
{
- return gf_dm_sess_set_range((GF_DownloadSession *)session, start_range, end_range);
+ return gf_dm_sess_set_range((GF_DownloadSession *)session, start_range, end_range, discontinue_cache);
}
GF_Err mpdin_dash_io_init(GF_DASHFileIO *dashio, GF_DASHFileIOSession session)
{
@@ -404,8 +410,7 @@ GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_
/*select input services if possible*/
for (i=0; idash); i++) {
- const char *mime, *init_segment;
-
+ const char *mime, *init_segment;
if (!gf_dash_is_group_selected(mpdin->dash, i))
continue;
@@ -422,7 +427,14 @@ GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_
GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD_IN] Unable to connect input service to %s\n", init_segment));
gf_dash_group_select(mpdin->dash, i, 0);
} else {
+ u32 w, h;
group->service_connected = 1;
+ w = h = 0;
+ gf_dash_group_get_video_info(mpdin->dash, i, &w, &h);
+ if (w && h && w>mpdin->width && h>mpdin->height) {
+ mpdin->width = w;
+ mpdin->height = h;
+ }
}
}
}
@@ -521,6 +533,19 @@ GF_Err MPD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const c
else if (opt && !strcmp(opt, "minQuality")) first_select_mode = GF_DASH_SELECT_QUALITY_LOWEST;
else if (opt && !strcmp(opt, "maxQuality")) first_select_mode = GF_DASH_SELECT_QUALITY_HIGHEST;
else first_select_mode = GF_DASH_SELECT_BANDWIDTH_LOWEST;
+
+ opt = gf_modules_get_option((GF_BaseInterface *)plug, "DASH", "MemoryStorage");
+ if (!opt) gf_modules_set_option((GF_BaseInterface *)plug, "DASH", "MemoryStorage", "no");
+ mpdin->memory_storage = (opt && !strcmp(opt, "yes")) ? 1 : 0;
+
+ opt = gf_modules_get_option((GF_BaseInterface *)plug, "DASH", "UseMaxResolution");
+ if (!opt) gf_modules_set_option((GF_BaseInterface *)plug, "DASH", "UseMaxResolution", "yes");
+ mpdin->use_max_res = (!opt || !strcmp(opt, "yes")) ? 1 : 0;
+
+ opt = gf_modules_get_option((GF_BaseInterface *)plug, "DASH", "ImmediateSwitching");
+ if (!opt) gf_modules_set_option((GF_BaseInterface *)plug, "DASH", "ImmediateSwitching", "no");
+ mpdin->immediate_switch = (opt && !strcmp(opt, "yes")) ? 1 : 0;
+
mpdin->in_seek = 0;
mpdin->previous_start_range = -1;
@@ -535,7 +560,7 @@ GF_Err MPD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const c
/*dash thread starts at the end of gf_dash_open */
e = gf_dash_open(mpdin->dash, url);
- if (!mpdin->dash) {
+ if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[MPD_IN] Error - cannot initialize DASH Client for %s: %s\n", url, gf_error_to_string(e) ));
gf_term_on_connect(mpdin->service, NULL, e);
return GF_OK;
@@ -549,14 +574,17 @@ static GF_Descriptor *MPD_GetServiceDesc(GF_InputService *plug, u32 expect_type,
GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv;
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Service Description request from terminal for %s\n", sub_url));
for (i=0; idash); i++) {
+ GF_Descriptor *desc;
GF_MPDGroup *mudta;
if (!gf_dash_is_group_selected(mpdin->dash, i))
continue;
mudta = gf_dash_get_group_udta(mpdin->dash, i);
if (!mudta) continue;
if (mudta->service_descriptor_fetched) continue;
- mudta->service_descriptor_fetched = 1;
- return mudta->segment_ifce->GetServiceDescriptor(mudta->segment_ifce, expect_type, sub_url);
+
+ desc = mudta->segment_ifce->GetServiceDescriptor(mudta->segment_ifce, expect_type, sub_url);
+ if (desc) mudta->service_descriptor_fetched = 1;
+ return desc;
}
return NULL;
}
@@ -612,8 +640,13 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
}
return GF_NOT_SUPPORTED;
+ case GF_NET_SERVICE_HAS_FORCED_VIDEO_SIZE:
+ com->par.width = mpdin->use_max_res ? mpdin->width : 0;
+ com->par.height = mpdin->use_max_res ? mpdin->height : 0;
+ return GF_OK;
+
case GF_NET_SERVICE_QUALITY_SWITCH:
- gf_dash_switch_quality(mpdin->dash, com->switch_quality.up);
+ gf_dash_switch_quality(mpdin->dash, com->switch_quality.up, mpdin->immediate_switch);
return GF_OK;
}
/*not supported*/
diff --git a/modules/mpegts_in/mpegts_in.c b/modules/mpegts_in/mpegts_in.c
index a3e8421..bbf866e 100644
--- a/modules/mpegts_in/mpegts_in.c
+++ b/modules/mpegts_in/mpegts_in.c
@@ -181,6 +181,10 @@ static GF_ObjectDescriptor *MP2TS_GetOD(M2TSIn *m2ts, GF_M2TS_PES *stream, char
esd->decoderConfig->streamType = GF_STREAM_VISUAL;
esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_AVC;
break;
+ case GF_M2TS_VIDEO_HEVC:
+ esd->decoderConfig->streamType = GF_STREAM_VISUAL;
+ esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_HEVC;
+ break;
case GF_M2TS_AUDIO_MPEG1:
esd->decoderConfig->streamType = GF_STREAM_AUDIO;
esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG1;
@@ -894,6 +898,9 @@ static GF_Descriptor *M2TS_GetServiceDesc(GF_InputService *plug, u32 expect_type
return desc;
}
}
+ /*if we expect scene, return NULL and repost a connection ack when we get the PMT*/
+ if (expect_type==GF_MEDIA_OBJECT_SCENE)
+ return NULL;
if (m2ts->epg_requested) {
GF_ObjectDescriptor *od = M2TS_GenerateEPG_OD(m2ts);
m2ts->epg_requested = 0;
diff --git a/modules/opensvc_dec/opensvc_dec.c b/modules/opensvc_dec/opensvc_dec.c
index 0690d0e..191c4b6 100644
--- a/modules/opensvc_dec/opensvc_dec.c
+++ b/modules/opensvc_dec/opensvc_dec.c
@@ -182,12 +182,15 @@ static GF_Err OSVC_SetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability capa
OSVCDec *ctx = (OSVCDec*) ifcg->privateStack;
switch (capability.CapCode) {
case GF_CODEC_MEDIA_SWITCH_QUALITY:
+
if (capability.cap.valueInt) {
- // set layer up (command=1)
- UpdateLayer( ctx->DqIdTable, &ctx->CurrDqId, &ctx->TemporalCom, &ctx->TemporalId, ctx->MaxDqId, 1 );
+ if (ctx->CurrDqId < ctx->MaxDqId)
+ // set layer up (command=1)
+ UpdateLayer( ctx->DqIdTable, &ctx->CurrDqId, &ctx->TemporalCom, &ctx->TemporalId, ctx->MaxDqId, 1 );
} else {
- // set layer down (command=0)
- UpdateLayer( ctx->DqIdTable, &ctx->CurrDqId, &ctx->TemporalCom, &ctx->TemporalId, ctx->MaxDqId, 0 );
+ if (ctx->CurrDqId > 0)
+ // set layer down (command=0)
+ UpdateLayer( ctx->DqIdTable, &ctx->CurrDqId, &ctx->TemporalCom, &ctx->TemporalId, ctx->MaxDqId, 0 );
}
return GF_OK;
}
@@ -207,6 +210,7 @@ static GF_Err OSVC_ProcessData(GF_MediaDecoder *ifcg,
OPENSVCFRAME pic;
int Layer[4];
OSVCDec *ctx = (OSVCDec*) ifcg->privateStack;
+ u32 curMaxDqId = ctx->MaxDqId;
if (!ES_ID || (ES_ID!=ctx->ES_ID) || !ctx->codec) {
*outBufferLength = 0;
@@ -217,25 +221,37 @@ static GF_Err OSVC_ProcessData(GF_MediaDecoder *ifcg,
return GF_BUFFER_TOO_SMALL;
}
+ ctx->MaxDqId = GetDqIdMax(inBuffer, inBufferLength, ctx->nalu_size_length, ctx->DqIdTable, ctx->nalu_size_length ? 1 : 0);
+ if(!ctx->InitParseAU){
+ if (ctx->MaxDqId == -1) {
+ //AVC stream in a h264 file
+ ctx->MaxDqId = 0;
+ } else {
+ //Firts time only, we parse the first AU to know the file configuration
+ //does not need to ba called again ever after, unless SPS or PPS changed
+ ParseAuPlayers(ctx->codec, inBuffer, inBufferLength, ctx->nalu_size_length, ctx->nalu_size_length ? 1 : 0);
+ }
+ ctx->InitParseAU = 1;
+ }
+/*
+ if (curMaxDqId != ctx->MaxDqId)
+ {
+ if (ctx->MaxDqId == -1)
+ ctx->MaxDqId = 0;
+ else
+ ParseAuPlayers(ctx->codec, inBuffer, inBufferLength, ctx->nalu_size_length, ctx->nalu_size_length ? 1 : 0);
+ ctx->CurrDqId = ctx->MaxDqId;
+ }
+// SetCommandLayer(Layer, ctx->MaxDqId, ctx->CurrDqId, &ctx->TemporalCom, ctx->TemporalId);
+*/
+ ctx->TemporalCom = 0;
+ SetCommandLayer(Layer, ctx->MaxDqId, ctx->MaxDqId, &ctx->TemporalCom, 0);
+
got_pic = 0;
if (ctx->nalu_size_length) {
u32 i, nalu_size = 0;
u8 *ptr = inBuffer;
- ctx->MaxDqId = GetDqIdMax(inBuffer, inBufferLength, ctx->nalu_size_length, ctx->DqIdTable, 1);
- if(!ctx->InitParseAU){
- if (ctx->MaxDqId == -1) {
- //AVC stream in a h264 file
- ctx->MaxDqId = 0;
- } else {
- //Firts time only, we parse the first AU to know the file configuration
- //does not need to ba called again ever after, unless SPS or PPS changed
- ParseAuPlayers(ctx->codec, inBuffer, inBufferLength, ctx->nalu_size_length, 1);
- }
- ctx->InitParseAU = 1;
- }
- SetCommandLayer(Layer, ctx->MaxDqId, ctx->CurrDqId, &ctx->TemporalCom, ctx->TemporalId);
-
while (inBufferLength) {
for (i=0; inalu_size_length; i++) {
nalu_size = (nalu_size<<8) + ptr[i];
@@ -256,7 +272,7 @@ static GF_Err OSVC_ProcessData(GF_MediaDecoder *ifcg,
}
if (got_pic!=1) return GF_OK;
- if ((pic.Width != ctx->width) || (pic.Height!=ctx->height)) {
+ if ((curMaxDqId != ctx->MaxDqId) || (pic.Width != ctx->width) || (pic.Height!=ctx->height)) {
ctx->width = pic.Width;
ctx->stride = pic.Width + 32;
ctx->height = pic.Height;
@@ -289,6 +305,9 @@ static u32 OSVC_CanHandleStream(GF_BaseDecoder *dec, u32 StreamType, GF_ESD *esd
GF_AVCConfig *cfg = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
if (!cfg) return GF_CODEC_NOT_SUPPORTED;
+ if (esd->has_ref_base)
+ is_svc = 1;
+
/*decode all NALUs*/
count = gf_list_count(cfg->sequenceParameterSets);
for (i=0; im_device->GetFriendlyName()) );
+ VPASSIGN( STRING_TO_JSVAL( JS_NewStringCopyZ(c, dev->m_device->GetFriendlyName()) ) );
}
else if (!strcmp(prop_name, "UUID")) {
- *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, dev->m_device->GetUUID()) );
+ VPASSIGN( STRING_TO_JSVAL( JS_NewStringCopyZ(c, dev->m_device->GetUUID()) ) );
}
else if (!strcmp(prop_name, "PresentationURL")) {
- *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, dev->m_device->m_PresentationURL) );
+ VPASSIGN( STRING_TO_JSVAL( JS_NewStringCopyZ(c, dev->m_device->m_PresentationURL) ) );
}
else if (!strcmp(prop_name, "ServicesCount")) {
u32 count = gf_list_count(dev->m_Services);
@@ -555,7 +555,7 @@ static SMJS_DECL_FUNC_PROP_GET( upnpdevice_getProperty)
dev->RefreshServiceList();
count = gf_list_count(dev->m_Services);
}
- *vp = INT_TO_JSVAL(count);
+ VPASSIGN( INT_TO_JSVAL(count) );
}
SMJS_FREE(c, prop_name);
return JS_TRUE;
@@ -663,22 +663,22 @@ static SMJS_DECL_FUNC_PROP_GET( upnp_getProperty)
if (!prop_name) return JS_FALSE;
if (!strcmp(prop_name, "MediaRendererEnabled")) {
- *vp = BOOLEAN_TO_JSVAL( upnp->m_pMediaRenderer ? JS_TRUE : JS_FALSE );
+ VPASSIGN( BOOLEAN_TO_JSVAL( upnp->m_pMediaRenderer ? JS_TRUE : JS_FALSE ) );
}
else if (!strcmp(prop_name, "MediaServerEnabled")) {
- *vp = BOOLEAN_TO_JSVAL( upnp->m_pMediaServer ? JS_TRUE : JS_FALSE);
+ VPASSIGN( BOOLEAN_TO_JSVAL( upnp->m_pMediaServer ? JS_TRUE : JS_FALSE) );
}
else if (!strcmp(prop_name, "MediaControlEnabled")) {
- *vp = BOOLEAN_TO_JSVAL( upnp->m_pAVCtrlPoint ? JS_TRUE : JS_FALSE);
+ VPASSIGN( BOOLEAN_TO_JSVAL( upnp->m_pAVCtrlPoint ? JS_TRUE : JS_FALSE) );
}
else if (!strcmp(prop_name, "MediaServersCount")) {
- *vp = INT_TO_JSVAL( upnp->m_pAVCtrlPoint ? gf_list_count(upnp->m_pAVCtrlPoint->m_MediaServers) : 0);
+ VPASSIGN( INT_TO_JSVAL( upnp->m_pAVCtrlPoint ? gf_list_count(upnp->m_pAVCtrlPoint->m_MediaServers) : 0) );
}
else if (!strcmp(prop_name, "MediaRenderersCount")) {
- *vp = INT_TO_JSVAL( upnp->m_pAVCtrlPoint ? gf_list_count(upnp->m_pAVCtrlPoint->m_MediaRenderers) : 0);
+ VPASSIGN( INT_TO_JSVAL( upnp->m_pAVCtrlPoint ? gf_list_count(upnp->m_pAVCtrlPoint->m_MediaRenderers) : 0) );
}
else if (!strcmp(prop_name, "DevicesCount")) {
- *vp = INT_TO_JSVAL( upnp->m_pGenericController ? gf_list_count(upnp->m_pGenericController->m_Devices) : 0);
+ VPASSIGN( INT_TO_JSVAL( upnp->m_pGenericController ? gf_list_count(upnp->m_pGenericController->m_Devices) : 0) );
}
SMJS_FREE(c, prop_name);
return JS_TRUE;
@@ -699,18 +699,18 @@ static SMJS_DECL_FUNC_PROP_SET(upnp_setProperty)
if (!prop_name) return JS_FALSE;
if (upnp->m_pMediaRenderer ) {
- if (!strcmp(prop_name, "MovieDuration") && JSVAL_IS_DOUBLE(*vp)) {
+ if (!strcmp(prop_name, "MovieDuration") && JSVAL_IS_DOUBLE( VPGET() )) {
jsdouble d;
- JS_ValueToNumber(c, *vp, &d);
+ JS_ValueToNumber(c, VPGET(), &d);
upnp->m_pMediaRenderer->SetDuration(d, 1);
}
- else if (!strcmp(prop_name, "MovieTime") && JSVAL_IS_DOUBLE(*vp)) {
+ else if (!strcmp(prop_name, "MovieTime") && JSVAL_IS_DOUBLE( VPGET() )) {
jsdouble d;
- JS_ValueToNumber(c, *vp, &d);
+ JS_ValueToNumber(c, VPGET(), &d);
upnp->m_pMediaRenderer->SetTime(d);
}
- else if (!strcmp(prop_name, "MovieURL") && JSVAL_IS_STRING(*vp) ) {
- char *url = SMJS_CHARS(c, *vp);
+ else if (!strcmp(prop_name, "MovieURL") && JSVAL_IS_STRING( VPGET() ) ) {
+ char *url = SMJS_CHARS(c, VPGET() );
if (url) upnp->m_pMediaRenderer->SetConnected(url);
SMJS_FREE(c, url);
}
@@ -1454,7 +1454,7 @@ Bool GF_UPnP::LoadJS(GF_TermExtJS *param)
{
u32 i, count;
JSPropertySpec upnpClassProps[] = {
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec upnpClassFuncs[] = {
SMJS_FUNCTION_SPEC("BindRenderer", upnp_bind_renderer, 0),
@@ -1522,7 +1522,7 @@ Bool GF_UPnP::LoadJS(GF_TermExtJS *param)
/*setup JS bindings*/
JSPropertySpec upnpDeviceClassProps[] = {
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec upnpDeviceClassFuncs[] = {
SMJS_FUNCTION_SPEC("FindService", upnp_device_find_service, 0),
diff --git a/modules/platinum/GPACPlatinum.h b/modules/platinum/GPACPlatinum.h
index 74890ff..1264017 100644
--- a/modules/platinum/GPACPlatinum.h
+++ b/modules/platinum/GPACPlatinum.h
@@ -141,6 +141,15 @@ public:
#ifdef GPAC_HAS_SPIDERMONKEY
SMJS_DECL_FUNC_PROP_GET( upnpservice_getProperty);
+
+#ifdef USE_FFDEV_17
+ #define VPASSIGN(__b) __vp.set( __b )
+ #define VPGET() (jsval) __vp
+#else
+ #define VPASSIGN(__b) *vp = __b
+ #define VPGET() *vp
+#endif
+
#endif
void format_time_string(char *str, Double dur);
diff --git a/modules/platinum/GenericDevice.cpp b/modules/platinum/GenericDevice.cpp
index 33e077d..ee11459 100644
--- a/modules/platinum/GenericDevice.cpp
+++ b/modules/platinum/GenericDevice.cpp
@@ -261,10 +261,10 @@ SMJS_DECL_FUNC_PROP_GET( upnpservice_getProperty)
if (!prop_name) return JS_FALSE;
if (!strcmp(prop_name, "Device")) {
- *vp = OBJECT_TO_JSVAL(service->m_device->obj);
+ VPASSIGN( OBJECT_TO_JSVAL(service->m_device->obj) );
}
else if (!strcmp(prop_name, "ModifiedStateVariablesCount")) {
- *vp = INT_TO_JSVAL(service->vars ? service->vars->GetItemCount() : 0);
+ VPASSIGN( INT_TO_JSVAL(service->vars ? service->vars->GetItemCount() : 0) );
}
SMJS_FREE(c, prop_name);
diff --git a/modules/widgetman/widget.c b/modules/widgetman/widget.c
index dc62a38..502dc22 100644
--- a/modules/widgetman/widget.c
+++ b/modules/widgetman/widget.c
@@ -386,6 +386,7 @@ SMJS_FUNC_PROP_SET( widget_setProperty)
/*avoids GCC warning*/
if (!obj) obj = NULL;
if (!id) id=0;
+ if (!vp) vp=0;
return JS_TRUE;
}
@@ -419,7 +420,7 @@ void widget_load(GF_WidgetManager *wm, GF_SceneGraph *scene, JSContext *c, JSObj
} else {
JSPropertySpec widgetClassProps[] = {
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec widgetClassFuncs[] = {
/*W3C*/
diff --git a/modules/widgetman/widgetman.c b/modules/widgetman/widgetman.c
index 9e25943..7f602b6 100644
--- a/modules/widgetman/widgetman.c
+++ b/modules/widgetman/widgetman.c
@@ -3497,7 +3497,7 @@ static void widgetmanager_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene,
GF_JSAPIParam par;
JSPropertySpec wmClassProps[] = {
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec wmClassFuncs[] = {
SMJS_FUNCTION_SPEC("initialize", wm_initialize, 0),
@@ -3545,7 +3545,7 @@ static void widgetmanager_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene,
{
JSPropertySpec wmWidgetClassProps[] = {
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec wmWidgetClassFuncs[] = {
SMJS_FUNCTION_SPEC("activate", wm_widget_activate, 1),
diff --git a/src/Makefile b/src/Makefile
index 318b782..733ce98 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -37,10 +37,13 @@ LIBGPAC_BIFS=bifs/arith_decoder.o bifs/bifs_codec.o bifs/bifs_node_tables.o bifs
endif
## libgpac objects gathering: src/isomedia
-LIBGPAC_ISOM=isomedia/avc_ext.o isomedia/box_code_3gpp.o isomedia/box_code_adobe.o isomedia/box_code_apple.o isomedia/box_code_base.o isomedia/box_code_drm.o isomedia/box_code_meta.o isomedia/box_dump.o isomedia/box_funcs.o isomedia/data_map.o isomedia/drm_sample.o isomedia/isom_intern.o isomedia/isom_read.o isomedia/isom_store.o isomedia/isom_write.o isomedia/media.o isomedia/media_odf.o isomedia/meta.o isomedia/movie_fragments.o isomedia/sample_descs.o isomedia/stbl_read.o isomedia/stbl_write.o isomedia/track.o isomedia/tx3g.o isomedia/generic_subtitle.o
+LIBGPAC_ISOM=isomedia/avc_ext.o isomedia/box_code_3gpp.o isomedia/box_code_apple.o isomedia/box_code_base.o isomedia/box_code_drm.o isomedia/box_code_meta.o isomedia/box_dump.o isomedia/box_funcs.o isomedia/data_map.o isomedia/drm_sample.o isomedia/isom_intern.o isomedia/isom_read.o isomedia/isom_store.o isomedia/isom_write.o isomedia/media.o isomedia/media_odf.o isomedia/meta.o isomedia/movie_fragments.o isomedia/sample_descs.o isomedia/stbl_read.o isomedia/stbl_write.o isomedia/track.o isomedia/tx3g.o isomedia/generic_subtitle.o
ifeq ($(DISABLE_ISOFF_HINT), no)
LIBGPAC_ISOM+=isomedia/hint_track.o isomedia/hinting.o
endif
+ifeq ($(DISABLE_ISOM_ADOBE), no)
+LIBGPAC_ISOM+=isomedia/box_code_adobe.o
+endif
## libgpac objects gathering: src/odf
LIBGPAC_ODF=odf/desc_private.o odf/descriptors.o odf/odf_code.o odf/odf_codec.o odf/odf_command.o odf/qos.o odf/slc.o
diff --git a/src/compositor/audio_mixer.c b/src/compositor/audio_mixer.c
index 42010d5..fa471a9 100644
--- a/src/compositor/audio_mixer.c
+++ b/src/compositor/audio_mixer.c
@@ -52,6 +52,8 @@ typedef struct
Fixed speed;
Fixed pan[6];
+
+ Bool muted;
} MixerInput;
struct __audiomix
@@ -578,6 +580,7 @@ u32 gf_mixer_get_output(GF_AudioMixer *am, void *buffer, u32 buffer_size, u32 de
return 0;
}
+ single_source->muted = single_source->src->IsMuted(single_source->src->callback);
/*this happens if input SR cannot be mapped to output audio hardware*/
if (single_source->src->samplerate != am->sample_rate) goto do_mix;
/*note we don't check output cfg: if the number of channel is the same then the channel cfg is the
@@ -590,7 +593,7 @@ single_source_mix:
ptr = (char *)buffer;
in_size = buffer_size;
- is_muted = single_source->src->IsMuted(single_source->src->callback);
+ is_muted = single_source->muted;
while (buffer_size) {
data = single_source->src->FetchFrame(single_source->src->callback, &size, delay);
@@ -631,7 +634,8 @@ do_mix:
single_source = NULL;
for (i=0; isources, i);
- if (in->src->IsMuted(in->src->callback)) continue;
+ in->muted = in->src->IsMuted(in->src->callback);
+ if (in->muted) continue;
if (in->buffer_size < nb_samples) {
for (j=0; jsrc->GetConfig(in->src, 0)) {
- nb_act_src = 0;
- am->must_reconfig = 1;
- /*if main mixer reconfig asap*/
- if (am->ar) gf_mixer_reconfig(am);
- break;
+ if (!am->must_reconfig) {
+ am->must_reconfig = 1;
+ /*if main mixer reconfig asap*/
+ if (am->ar) gf_mixer_reconfig(am);
+ }
+ //however keep the current mixer config and output some audio ...
+// nb_act_src = 0;
+// break;
+ in->muted = 1;
+ continue;
} else if (in->speed==0) {
in->out_samples_to_write = 0;
} else {
@@ -690,6 +699,10 @@ do_mix:
/*fill*/
for (i=0; isources, i);
+ if (in->muted) {
+ in->out_samples_to_write = 0;
+ continue;
+ }
if (in->out_samples_to_write>in->out_samples_written) {
gf_mixer_fetch_input(am, in, delay + 8000 * i / am->bits_per_sample / am->sample_rate / am->nb_channels);
if (in->out_samples_to_write>in->out_samples_written) nb_to_fill++;
@@ -698,6 +711,7 @@ do_mix:
/*release - this is done in 2 steps in case 2 audio object use the same source...*/
for (i=0; isources, i);
+ if (in->muted) continue;
if (in->in_bytes_used) in->src->ReleaseFrame(in->src->callback, in->in_bytes_used-1);
in->in_bytes_used = 0;
}
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 04891c8..a327371 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -788,7 +788,7 @@ static void gf_sc_reset(GF_Compositor *compositor)
compositor->focus_node = NULL;
compositor->focus_text_type = 0;
compositor->frame_number = 0;
- compositor->video_memory = 0;
+ compositor->video_memory = compositor->was_system_memory ? 0 : 1;
compositor->rotation = 0;
gf_list_reset(compositor->focus_ancestors);
diff --git a/src/compositor/compositor_2d.c b/src/compositor/compositor_2d.c
index 9b27324..4e6de5d 100644
--- a/src/compositor/compositor_2d.c
+++ b/src/compositor/compositor_2d.c
@@ -783,6 +783,8 @@ Bool compositor_2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_st
GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor)
{
+ u32 old_vp_width, old_vp_height;
+ Bool changed = 0;
Double ratio;
GF_Event evt;
GF_Err e;
@@ -793,6 +795,9 @@ GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor)
compositor->vp_x = compositor->vp_y = 0;
scaleX = scaleY = FIX_ONE;
+ old_vp_width = compositor->vp_width;
+ old_vp_height = compositor->vp_height;
+
/*force complete clean*/
compositor->traverse_state->invalidate_all = 1;
@@ -892,21 +897,32 @@ GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor)
}
#endif
+ if (compositor->was_system_memory != evt.setup.system_memory) changed = 1;
+ else if (old_vp_width != compositor->vp_width) changed=1;
+ else if (old_vp_height != compositor->vp_height) changed=1;
+ else if (compositor->was_opengl != evt.setup.opengl_mode) changed=1;
+
- GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring display size %d x %d - opengl %s - use %s memory\n", evt.setup.width, evt.setup.height,
- (evt.setup.opengl_mode==2) ? "Offscreen" : (evt.setup.opengl_mode==1) ? "yes" : "no", evt.setup.system_memory ? "systems" : "video"
- ));
+ if (changed) {
+ GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor2D] Reconfiguring display size %d x %d - opengl %s - use %s memory\n", evt.setup.width, evt.setup.height,
+ (evt.setup.opengl_mode==2) ? "Offscreen" : (evt.setup.opengl_mode==1) ? "yes" : "no", evt.setup.system_memory ? "systems" : "video"
+ ));
- e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
- if (e) return e;
+ e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
+ if (e) return e;
- if (compositor->has_size_info) {
- compositor->traverse_state->vp_size.x = INT2FIX(compositor->scene_width);
- compositor->traverse_state->vp_size.y = INT2FIX(compositor->scene_height);
- } else {
- compositor->traverse_state->vp_size.x = INT2FIX(compositor->output_width);
- compositor->traverse_state->vp_size.y = INT2FIX(compositor->output_height);
+ if (compositor->has_size_info) {
+ compositor->traverse_state->vp_size.x = INT2FIX(compositor->scene_width);
+ compositor->traverse_state->vp_size.y = INT2FIX(compositor->scene_height);
+ } else {
+ compositor->traverse_state->vp_size.x = INT2FIX(compositor->output_width);
+ compositor->traverse_state->vp_size.y = INT2FIX(compositor->output_height);
+ }
+ compositor->was_opengl = evt.setup.opengl_mode;
+ compositor->was_system_memory = evt.setup.system_memory;
+
}
+
/*set scale factor*/
compositor_set_ar_scale(compositor, scaleX, scaleY);
return GF_OK;
diff --git a/src/compositor/texturing.c b/src/compositor/texturing.c
index 9c90f23..28599fa 100644
--- a/src/compositor/texturing.c
+++ b/src/compositor/texturing.c
@@ -177,14 +177,12 @@ void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync)
/*check init flag*/
if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) {
- /*if we had a texture this means the object has changed - delete texture and force next frame
- composition (this will take care of OD reuse)*/
+ /*if we had a texture this means the object has changed - delete texture and resetup. Do not skip
+ texture update as this may lead to an empty rendering pass (blank frame for this object), especially in DASH*/
if (txh->tx_io) {
gf_sc_texture_release(txh);
txh->data = NULL;
txh->needs_refresh = 1;
- gf_sc_invalidate(txh->compositor, NULL);
- return;
}
if (gf_mo_is_private_media(txh->stream)) {
setup_texture_object(txh, 1);
@@ -195,6 +193,7 @@ void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync)
/*if no frame or muted don't draw*/
if (!txh->data || !size) {
+ GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("No output frame available\n"));
/*TODO - check if this is needed */
if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
//txh->needs_refresh = 1;
diff --git a/src/export.cpp b/src/export.cpp
index 1027968..e8b9e55 100644
--- a/src/export.cpp
+++ b/src/export.cpp
@@ -84,8 +84,10 @@
#pragma comment (linker, EXPORT_SYMBOL(gf_prompt_get_char) )
#pragma comment (linker, EXPORT_SYMBOL(gf_prompt_set_echo_off) )
#pragma comment (linker, EXPORT_SYMBOL(gf_crc_32) )
+#ifndef GPAC_DISABLE_ZLIB
#pragma comment (linker, EXPORT_SYMBOL(gf_gz_compress_payload) )
#pragma comment (linker, EXPORT_SYMBOL(gf_gz_decompress_payload) )
+#endif
/* Memory */
#ifdef GPAC_MEMORY_TRACKING
@@ -635,6 +637,7 @@
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_decoder_config) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_reference_count) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_reference) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_reference_ID) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_has_track_reference) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_filename) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_brand_info) )
@@ -667,6 +670,7 @@
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_avc_config_get) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_svc_config_get) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_3gp_config_get) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_isom_hevc_config_get) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_meta_item_count) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_meta_item_by_id) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_meta_item_info) )
@@ -694,7 +698,9 @@
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_rvc_config) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_sample_rap_roll_info) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_reset_fragment_info) )
-
+#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_track_original_id) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_nalu_extract_mode) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_nalu_extract_mode) )
# ifndef GPAC_DISABLE_ISOM_DUMP
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_dump) )
@@ -723,6 +729,7 @@
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_track_creation_time) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_track_enabled) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_track_id) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_isom_rewrite_track_dependencies) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_add_sample) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_add_sample_shadow) )
#pragma comment (linker, EXPORT_SYMBOL(gf_isom_append_sample_data) )
@@ -1088,6 +1095,7 @@
#ifndef GPAC_DISABLE_AV_PARSERS
#pragma comment (linker, EXPORT_SYMBOL(gf_avc_get_sps_info) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_avc_get_pps_info) )
#pragma comment (linker, EXPORT_SYMBOL(gf_avc_get_profile_name) )
#endif /*GPAC_DISABLE_AV_PARSERS*/
@@ -1731,6 +1739,16 @@
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_segment_switch_forced) )
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_current_segment_start_time) )
#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_presentation_time_offset) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_video_info) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_representation_info) )
+
+#pragma comment (linker, EXPORT_SYMBOL(gf_media_hevc_read_vps) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_media_hevc_read_sps) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_media_hevc_read_pps) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_odf_hevc_cfg_read) )
+#pragma comment (linker, EXPORT_SYMBOL(gf_odf_hevc_cfg_del) )
+
+#pragma comment (linker, EXPORT_SYMBOL(gf_media_nalu_next_start_code) )
#endif
diff --git a/src/ietf/rtp_streamer.c b/src/ietf/rtp_streamer.c
index 4d638a0..4324bb4 100644
--- a/src/ietf/rtp_streamer.c
+++ b/src/ietf/rtp_streamer.c
@@ -342,6 +342,8 @@ GF_RTPStreamer *gf_rtp_streamer_new_extended(u32 streamType, u32 oti, u32 timeSc
break;
case GF_ISOM_SUBTYPE_AVC_H264:
case GF_ISOM_SUBTYPE_AVC2_H264:
+ case GF_ISOM_SUBTYPE_AVC3_H264:
+ case GF_ISOM_SUBTYPE_AVC4_H264:
case GF_ISOM_SUBTYPE_SVC_H264:
{
required_rate = 90000; /* "90 kHz clock rate MUST be used"*/
diff --git a/src/isomedia/avc_ext.c b/src/isomedia/avc_ext.c
index e88e74d..970b83d 100644
--- a/src/isomedia/avc_ext.c
+++ b/src/isomedia/avc_ext.c
@@ -32,6 +32,369 @@
#ifndef GPAC_DISABLE_ISOM
+
+Bool gf_isom_is_nalu_based_entry(GF_MediaBox *mdia, GF_SampleEntryBox *_entry)
+{
+ GF_MPEGVisualSampleEntryBox *entry;
+ if (mdia->handler->handlerType != GF_ISOM_MEDIA_VISUAL) return 0;
+ entry = (GF_MPEGVisualSampleEntryBox*)_entry;
+ if (!entry) return 0;
+ if (entry->avc_config || entry->svc_config || entry->hevc_config) return 1;
+ return 0;
+}
+
+
+static void rewrite_nalus_list(GF_List *nalus, GF_BitStream *bs, Bool rewrite_start_codes, u32 nal_unit_size_field)
+{
+ u32 i, count = gf_list_count(nalus);
+ for (i=0; isize, 8*nal_unit_size_field);
+ gf_bs_write_data(bs, sl->data, sl->size);
+ }
+}
+
+static void merge_nalus_list(GF_List *src, GF_List *dst)
+{
+ u32 i, count = gf_list_count(src);
+ for (i=0; iavc_config) {
+ merge_nalus_list(entry->avc_config->config->sequenceParameterSets, sps);
+ merge_nalus_list(entry->avc_config->config->sequenceParameterSetExtensions, sps);
+ merge_nalus_list(entry->avc_config->config->pictureParameterSets, pps);
+ }
+ if (entry->svc_config) {
+ merge_nalus_list(entry->svc_config->config->sequenceParameterSets, sps);
+ merge_nalus_list(entry->svc_config->config->pictureParameterSets, pps);
+ }
+}
+
+
+/* Rewrite mode:
+ * mode = 0: playback
+ * mode = 1: streaming
+ */
+GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 sampleNumber, GF_MPEGVisualSampleEntryBox *entry)
+{
+ Bool is_hevc = 0;
+ GF_Err e = GF_OK;
+ GF_ISOSample *ref_samp;
+ GF_BitStream *src_bs, *ref_bs, *dst_bs;
+ u64 offset;
+ u32 ref_nalu_size, data_offset, data_length, copy_size, nal_size, max_size, di, nal_unit_size_field, cur_extract_mode, extractor_mode;
+ Bool rewrite_ps, rewrite_start_codes;
+ u8 ref_track_ID, ref_track_num;
+ s8 sample_offset, nal_type;
+ u32 nal_hdr;
+ char *buffer;
+ GF_ISOFile *file = mdia->mediaTrack->moov->mov;
+
+ src_bs = ref_bs = dst_bs = NULL;
+ ref_samp = NULL;
+ buffer = NULL;
+ rewrite_ps = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG) ? 1 : 0;
+ if (! sample->IsRAP) rewrite_ps = 0;
+ rewrite_start_codes = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG) ? 1 : 0;
+ extractor_mode = mdia->mediaTrack->extractor_mode&0x0000FFFF;
+
+ if (extractor_mode == GF_ISOM_NALU_EXTRACT_INSPECT) {
+ if (!rewrite_ps && !rewrite_start_codes)
+ return GF_OK;
+ }
+
+ if (!entry) return GF_BAD_PARAM;
+ nal_unit_size_field = 0;
+ /*if svc rewrire*/
+ if (entry->svc_config && entry->svc_config->config) nal_unit_size_field = entry->svc_config->config->nal_unit_size;
+ /*if mvc rewrire*/
+
+ /*otherwise do nothing*/
+ else if (!rewrite_ps && !rewrite_start_codes) {
+ return GF_OK;
+ }
+
+ if (!nal_unit_size_field) {
+ if (entry->avc_config) nal_unit_size_field = entry->avc_config->config->nal_unit_size;
+ else if (entry->hevc_config) {
+ nal_unit_size_field = entry->hevc_config->config->nal_unit_size;
+ is_hevc = 1;
+ }
+ }
+ if (!nal_unit_size_field) return GF_ISOM_INVALID_FILE;
+
+ dst_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
+ src_bs = gf_bs_new(sample->data, sample->dataLength, GF_BITSTREAM_READ);
+ max_size = 4096;
+
+ /*rewrite start code with NALU delim*/
+ if (rewrite_start_codes) {
+ gf_bs_write_int(dst_bs, 1, 32);
+ if (is_hevc) {
+ gf_bs_write_int(dst_bs, 0, 1);
+ gf_bs_write_int(dst_bs, GF_HEVC_NALU_ACCESS_UNIT, 6);
+ gf_bs_write_int(dst_bs, 0, 9);
+ /*pic-type - by default we signal all slice types possible*/
+ gf_bs_write_int(dst_bs, 2, 3);
+ gf_bs_write_int(dst_bs, 0, 5);
+ } else {
+ gf_bs_write_int(dst_bs, (sample->data[0] & 0x60) | GF_AVC_NALU_ACCESS_UNIT, 8);
+ gf_bs_write_int(dst_bs, 0xF0 , 8); /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/;
+ }
+ }
+
+ if (rewrite_ps) {
+ if (is_hevc) {
+ u32 i, count;
+ count = gf_list_count(entry->hevc_config->config->param_array);
+ for (i=0; ihevc_config->config->param_array, i);
+ rewrite_nalus_list(ar->nalus, dst_bs, rewrite_start_codes, nal_unit_size_field);
+ }
+
+ /*little optimization if we are not asked to start codes: copy over the sample*/
+ if (!rewrite_start_codes) {
+ gf_bs_write_data(dst_bs, sample->data, sample->dataLength);
+ gf_free(sample->data);
+ sample->data = NULL;
+ gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength);
+ gf_bs_del(src_bs);
+ gf_bs_del(dst_bs);
+ return GF_OK;
+ }
+ } else {
+
+ /*this is an SVC track: get all SPS/PPS from this track down to the base layer and rewrite them*/
+ if (mdia->mediaTrack->has_base_layer) {
+ u32 j;
+ GF_List *nalu_sps = gf_list_new();
+ GF_List *nalu_pps = gf_list_new();
+ GF_TrackReferenceTypeBox *dpnd = NULL;
+ Track_FindRef(mdia->mediaTrack, GF_ISOM_REF_SCAL, &dpnd);
+
+#if 0
+ /*get all upper layers with SCAL reference to this track*/
+ for (j = 0; j < gf_isom_get_track_count(file); j++) {
+ if (gf_isom_has_track_reference(file, j+1, GF_ISOM_REF_SCAL, mdia->mediaTrack->Header->trackID)) {
+ u32 tkID;
+ GF_TrackBox *base_track;
+ GF_MPEGVisualSampleEntryBox *base_entry;
+ gf_isom_get_reference_ID(file, j+1, GF_ISOM_REF_SCAL, 1, &tkID);
+
+ base_track = GetTrackbyID(mdia->mediaTrack->moov, tkID);
+ base_entry = base_track ? gf_list_get(base_track->Media->information->sampleTable->SampleDescription->other_boxes, 0) : NULL;
+ if (base_entry)
+ merge_nalus(base_entry, nalu_sps, nalu_pps);
+ }
+ }
+
+#endif
+
+ merge_nalus(entry, nalu_sps, nalu_pps);
+ if (dpnd) {
+ for (j=0; jtrackIDCount; j++) {
+ GF_TrackBox *base_track = GetTrackbyID(mdia->mediaTrack->moov, dpnd->trackIDs[j]);
+ GF_MPEGVisualSampleEntryBox *base_entry = base_track ? gf_list_get(base_track->Media->information->sampleTable->SampleDescription->other_boxes, 0) : NULL;
+ if (base_entry)
+ merge_nalus(base_entry, nalu_sps, nalu_pps);
+ }
+ }
+
+ //rewrite nalus
+ rewrite_nalus_list(nalu_sps, dst_bs, rewrite_start_codes, nal_unit_size_field);
+ rewrite_nalus_list(nalu_pps, dst_bs, rewrite_start_codes, nal_unit_size_field);
+
+ gf_list_del(nalu_sps);
+ gf_list_del(nalu_pps);
+ } else {
+
+ if (entry->avc_config) {
+ rewrite_nalus_list(entry->avc_config->config->sequenceParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
+ rewrite_nalus_list(entry->avc_config->config->pictureParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
+ rewrite_nalus_list(entry->avc_config->config->sequenceParameterSetExtensions, dst_bs, rewrite_start_codes, nal_unit_size_field);
+ }
+
+ /*add svc config */
+ if (entry->svc_config) {
+ rewrite_nalus_list(entry->svc_config->config->sequenceParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
+ rewrite_nalus_list(entry->svc_config->config->pictureParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
+ }
+
+ /*little optimization if we are not asked to rewrite extractors or start codes: copy over the sample*/
+ if (!entry->svc_config && !rewrite_start_codes) {
+ gf_bs_write_data(dst_bs, sample->data, sample->dataLength);
+ gf_free(sample->data);
+ sample->data = NULL;
+ gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength);
+ gf_bs_del(src_bs);
+ gf_bs_del(dst_bs);
+ return GF_OK;
+ }
+
+ }
+ }
+ }
+
+ buffer = (char *)gf_malloc(sizeof(char)*max_size);
+
+ while (gf_bs_available(src_bs))
+ {
+ nal_size = gf_bs_read_int(src_bs, 8*nal_unit_size_field);
+ if (nal_size>max_size) {
+ buffer = (char*) gf_realloc(buffer, sizeof(char)*nal_size);
+ max_size = nal_size;
+ }
+ if (is_hevc) {
+ nal_hdr = gf_bs_read_u16(src_bs);
+ nal_type = (nal_hdr&0x7E00) >> 9;
+ } else {
+ nal_hdr = gf_bs_read_u8(src_bs);
+ nal_type = nal_hdr & 0x1F;
+ }
+
+ if (is_hevc) {
+ /*we already wrote this stuff*/
+ if (nal_type==GF_HEVC_NALU_ACCESS_UNIT)
+ continue;
+
+ /*rewrite nal*/
+ gf_bs_read_data(src_bs, buffer, nal_size-2);
+ if (rewrite_start_codes)
+ gf_bs_write_u32(dst_bs, 1);
+ else
+ gf_bs_write_int(dst_bs, nal_size, 8*nal_unit_size_field);
+
+ gf_bs_write_u16(dst_bs, nal_hdr);
+ gf_bs_write_data(dst_bs, buffer, nal_size-2);
+
+ continue;
+ }
+
+ /*we already wrote this stuff*/
+ if (nal_type==GF_AVC_NALU_ACCESS_UNIT)
+ continue;
+
+ //extractor
+ if (nal_type == 31) {
+ switch (extractor_mode) {
+ case 0:
+ gf_bs_read_int(src_bs, 24); //3 bytes of NALUHeader in extractor
+ ref_track_ID = gf_bs_read_u8(src_bs);
+ sample_offset = (s8) gf_bs_read_int(src_bs, 8);
+ data_offset = gf_bs_read_u32(src_bs);
+ data_length = gf_bs_read_u32(src_bs);
+
+ ref_track_num = gf_isom_get_track_by_id(file, ref_track_ID);
+ if (!ref_track_num) {
+ e = GF_BAD_PARAM;
+ goto exit;
+ }
+ cur_extract_mode = gf_isom_get_nalu_extract_mode(file, ref_track_num);
+ gf_isom_set_nalu_extract_mode(file, ref_track_num, GF_ISOM_NALU_EXTRACT_INSPECT);
+ ref_samp = gf_isom_get_sample(file, ref_track_num, sampleNumber+sample_offset, &di);
+ if (!ref_samp) {
+ e = GF_IO_ERR;
+ goto exit;
+ }
+ ref_bs = gf_bs_new(ref_samp->data, ref_samp->dataLength, GF_BITSTREAM_READ);
+ offset = 0;
+ while (gf_bs_available(ref_bs)) {
+ if (gf_bs_get_position(ref_bs) < data_offset) {
+ ref_nalu_size = gf_bs_read_int(ref_bs, 8*nal_unit_size_field);
+ offset += ref_nalu_size + nal_unit_size_field;
+ if ((offset > data_offset) || (offset >= gf_bs_get_size(ref_bs))) {
+ e = GF_BAD_PARAM;
+ goto exit;
+ }
+
+ e = gf_bs_seek(ref_bs, offset);
+ if (e)
+ goto exit;
+ continue;
+ }
+ ref_nalu_size = gf_bs_read_int(ref_bs, 8*nal_unit_size_field);
+ copy_size = data_length ? data_length : ref_nalu_size;
+ assert(copy_size <= ref_nalu_size);
+ nal_hdr = gf_bs_read_u8(ref_bs); //rewrite NAL type
+ if ((copy_size-1)>max_size) {
+ buffer = (char*)gf_realloc(buffer, sizeof(char)*(copy_size-1));
+ max_size = copy_size-1;
+ }
+ gf_bs_read_data(ref_bs, buffer, copy_size-1);
+
+ if (rewrite_start_codes)
+ gf_bs_write_u32(dst_bs, 1);
+ else
+ gf_bs_write_int(dst_bs, copy_size, 8*nal_unit_size_field);
+
+ gf_bs_write_u8(dst_bs, nal_hdr);
+ gf_bs_write_data(dst_bs, buffer, copy_size-1);
+ }
+
+ gf_isom_sample_del(&ref_samp);
+ ref_samp = NULL;
+ gf_bs_del(ref_bs);
+ ref_bs = NULL;
+ gf_isom_set_nalu_extract_mode(file, ref_track_num, cur_extract_mode);
+ break;
+ default:
+ //skip to end of this NALU
+ gf_bs_skip_bytes(src_bs, nal_size-1);
+ continue;
+ }
+ } else {
+ gf_bs_read_data(src_bs, buffer, nal_size-1);
+ if (rewrite_start_codes)
+ gf_bs_write_u32(dst_bs, 1);
+ else
+ gf_bs_write_int(dst_bs, nal_size, 8*nal_unit_size_field);
+
+ gf_bs_write_u8(dst_bs, nal_hdr);
+ gf_bs_write_data(dst_bs, buffer, nal_size-1);
+ }
+ }
+ /*done*/
+ gf_free(sample->data);
+ sample->data = NULL;
+ gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength);
+
+exit:
+ if (ref_samp) gf_isom_sample_del(&ref_samp);
+ if (src_bs) gf_bs_del(src_bs);
+ if (ref_bs) gf_bs_del(ref_bs);
+ if (dst_bs) gf_bs_del(dst_bs);
+ if (buffer) gf_free(buffer);
+ return e;
+}
+
+GF_HEVCConfig *HEVC_DuplicateConfig(GF_HEVCConfig *cfg)
+{
+ char *data;
+ u32 data_size;
+ GF_HEVCConfig *new_cfg;
+ GF_BitStream *bs;
+
+ if (!cfg) return NULL;
+ bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
+ gf_odf_hevc_cfg_write_bs(cfg, bs);
+
+ gf_bs_get_content(bs, &data, &data_size);
+ gf_bs_del(bs);
+ bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
+
+ new_cfg = gf_odf_hevc_cfg_read_bs(bs);
+ gf_bs_del(bs);
+ gf_free(data);
+ return new_cfg;
+}
+
static GF_AVCConfig *AVC_DuplicateConfig(GF_AVCConfig *cfg)
{
u32 i, count;
@@ -128,14 +491,41 @@ void AVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *avc)
gf_odf_avc_cfg_write(avcc, &avc->emul_esd->decoderConfig->decoderSpecificInfo->data, &avc->emul_esd->decoderConfig->decoderSpecificInfo->dataLength);
gf_odf_avc_cfg_del(avcc);
}
- } else {
+ } else if (avc->svc_config) {
svcc = AVC_DuplicateConfig(avc->svc_config->config);
gf_odf_avc_cfg_write(svcc, &avc->emul_esd->decoderConfig->decoderSpecificInfo->data, &avc->emul_esd->decoderConfig->decoderSpecificInfo->dataLength);
gf_odf_avc_cfg_del(svcc);
}
}
-GF_Err AVC_UpdateESD(GF_MPEGVisualSampleEntryBox *avc, GF_ESD *esd)
+void HEVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *hevc)
+{
+ if (hevc->emul_esd) gf_odf_desc_del((GF_Descriptor *)hevc->emul_esd);
+ hevc->emul_esd = gf_odf_desc_esd_new(2);
+ hevc->emul_esd->decoderConfig->streamType = GF_STREAM_VISUAL;
+ hevc->emul_esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_HEVC;
+ if (hevc->bitrate) {
+ hevc->emul_esd->decoderConfig->bufferSizeDB = hevc->bitrate->bufferSizeDB;
+ hevc->emul_esd->decoderConfig->avgBitrate = hevc->bitrate->avgBitrate;
+ hevc->emul_esd->decoderConfig->maxBitrate = hevc->bitrate->maxBitrate;
+ }
+ if (hevc->descr) {
+ u32 i=0;
+ GF_Descriptor *desc,*clone;
+ i=0;
+ while ((desc = (GF_Descriptor *)gf_list_enum(hevc->descr->descriptors, &i))) {
+ clone = NULL;
+ gf_odf_desc_copy(desc, &clone);
+ if (gf_odf_desc_add_desc((GF_Descriptor *)hevc->emul_esd, clone) != GF_OK)
+ gf_odf_desc_del(clone);
+ }
+ }
+ if (hevc->hevc_config && hevc->hevc_config->config) {
+ gf_odf_hevc_cfg_write(hevc->hevc_config->config, &hevc->emul_esd->decoderConfig->decoderSpecificInfo->data, &hevc->emul_esd->decoderConfig->decoderSpecificInfo->dataLength);
+ }
+}
+
+GF_Err AVC_HEVC_UpdateESD(GF_MPEGVisualSampleEntryBox *avc, GF_ESD *esd)
{
if (!avc->bitrate) avc->bitrate = (GF_MPEG4BitRateBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_BTRT);
if (avc->descr) gf_isom_box_del((GF_Box *) avc->descr);
@@ -178,14 +568,27 @@ GF_Err AVC_UpdateESD(GF_MPEGVisualSampleEntryBox *avc, GF_ESD *esd)
/*update GF_AVCConfig*/
if (!avc->svc_config) {
- if (!avc->avc_config) avc->avc_config = (GF_AVCConfigurationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_AVCC);
- if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) {
- if (avc->avc_config->config) gf_odf_avc_cfg_del(avc->avc_config->config);
- avc->avc_config->config = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
+ if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_HEVC) {
+ if (!avc->hevc_config) avc->hevc_config = (GF_HEVCConfigurationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_HVCC);
+ if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) {
+ if (avc->hevc_config->config) gf_odf_hevc_cfg_del(avc->hevc_config->config);
+ avc->hevc_config->config = gf_odf_hevc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
+ }
+ } else {
+ if (!avc->avc_config) avc->avc_config = (GF_AVCConfigurationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_AVCC);
+ if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) {
+ if (avc->avc_config->config) gf_odf_avc_cfg_del(avc->avc_config->config);
+ avc->avc_config->config = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
+ }
}
- gf_odf_desc_del((GF_Descriptor *)esd);
+
+ }
+ gf_odf_desc_del((GF_Descriptor *)esd);
+ if (avc->hevc_config) {
+ HEVC_RewriteESDescriptor(avc);
+ } else {
+ AVC_RewriteESDescriptor(avc);
}
- AVC_RewriteESDescriptor(avc);
return GF_OK;
}
@@ -234,12 +637,14 @@ static GF_Err gf_isom_avc_config_update_ex(GF_ISOFile *the_file, u32 trackNumber
e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
- if (!trak || !trak->Media || !cfg || !DescriptionIndex) return GF_BAD_PARAM;
+ if (!trak || !trak->Media || !DescriptionIndex) return GF_BAD_PARAM;
entry = (GF_MPEGVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, DescriptionIndex-1);
if (!entry) return GF_BAD_PARAM;
switch (entry->type) {
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
break;
default:
@@ -249,6 +654,7 @@ static GF_Err gf_isom_avc_config_update_ex(GF_ISOFile *the_file, u32 trackNumber
switch (op_type) {
/*AVCC replacement*/
case 0:
+ if (!cfg) return GF_BAD_PARAM;
if (!entry->avc_config) entry->avc_config = (GF_AVCConfigurationBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_AVCC);
if (entry->avc_config->config) gf_odf_avc_cfg_del(entry->avc_config->config);
entry->avc_config->config = AVC_DuplicateConfig(cfg);
@@ -256,6 +662,7 @@ static GF_Err gf_isom_avc_config_update_ex(GF_ISOFile *the_file, u32 trackNumber
break;
/*SVCC replacement*/
case 1:
+ if (!cfg) return GF_BAD_PARAM;
if (!entry->svc_config) entry->svc_config = (GF_AVCConfigurationBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_SVCC);
if (entry->svc_config->config) gf_odf_avc_cfg_del(entry->svc_config->config);
entry->svc_config->config = AVC_DuplicateConfig(cfg);
@@ -263,6 +670,7 @@ static GF_Err gf_isom_avc_config_update_ex(GF_ISOFile *the_file, u32 trackNumber
break;
/*SVCC replacement and AVC removal*/
case 2:
+ if (!cfg) return GF_BAD_PARAM;
if (entry->avc_config) {
gf_isom_box_del((GF_Box*)entry->avc_config);
entry->avc_config = NULL;
@@ -272,11 +680,45 @@ static GF_Err gf_isom_avc_config_update_ex(GF_ISOFile *the_file, u32 trackNumber
entry->svc_config->config = AVC_DuplicateConfig(cfg);
entry->type = GF_ISOM_BOX_TYPE_SVC1;
break;
+ /*AVCC removal and switch to avc3*/
+ case 3:
+ if (!entry->avc_config || !entry->avc_config->config)
+ return GF_BAD_PARAM;
+
+ if (entry->svc_config) {
+ gf_isom_box_del((GF_Box*)entry->svc_config);
+ entry->svc_config = NULL;
+ }
+
+ while (gf_list_count(entry->avc_config->config->sequenceParameterSets)) {
+ GF_AVCConfigSlot *sl = gf_list_get(entry->avc_config->config->sequenceParameterSets, 0);
+ gf_list_rem(entry->avc_config->config->sequenceParameterSets, 0);
+ if (sl->data) gf_free(sl->data);
+ gf_free(sl);
+ }
+
+ while (gf_list_count(entry->avc_config->config->pictureParameterSets)) {
+ GF_AVCConfigSlot *sl = gf_list_get(entry->avc_config->config->pictureParameterSets, 0);
+ gf_list_rem(entry->avc_config->config->pictureParameterSets, 0);
+ if (sl->data) gf_free(sl->data);
+ gf_free(sl);
+ }
+
+ if (entry->type == GF_ISOM_BOX_TYPE_AVC1)
+ entry->type = GF_ISOM_BOX_TYPE_AVC3;
+ else if (entry->type == GF_ISOM_BOX_TYPE_AVC2)
+ entry->type = GF_ISOM_BOX_TYPE_AVC4;
+ break;
}
AVC_RewriteESDescriptor(entry);
return GF_OK;
}
+GF_Err gf_isom_avc_set_inband_config(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
+{
+ return gf_isom_avc_config_update_ex(the_file, trackNumber, DescriptionIndex, NULL, 3);
+}
+
GF_EXPORT
GF_Err gf_isom_avc_config_update(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_AVCConfig *cfg)
{
@@ -303,6 +745,8 @@ GF_Err gf_isom_svc_config_del(GF_ISOFile *the_file, u32 trackNumber, u32 Descrip
switch (entry->type) {
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
break;
default:
@@ -334,7 +778,11 @@ GF_Err gf_isom_set_ipod_compatible(GF_ISOFile *the_file, u32 trackNumber)
switch (entry->type) {
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
break;
default:
return GF_OK;
@@ -380,6 +828,79 @@ GF_Err gf_isom_svc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AVCConfi
return e;
}
+GF_Err gf_isom_hevc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_HEVCConfig *cfg, char *URLname, char *URNname, u32 *outDescriptionIndex)
+{
+ GF_TrackBox *trak;
+ GF_Err e;
+ u32 dataRefIndex;
+ GF_MPEGVisualSampleEntryBox *entry;
+
+ e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
+ if (e) return e;
+
+ trak = gf_isom_get_track_from_file(the_file, trackNumber);
+ if (!trak || !trak->Media || !cfg) return GF_BAD_PARAM;
+
+ //get or create the data ref
+ e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
+ if (e) return e;
+ if (!dataRefIndex) {
+ e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
+ if (e) return e;
+ }
+ trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
+
+ //create a new entry
+ entry = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_HVC1);
+ if (!entry) return GF_OUT_OF_MEM;
+ entry->hevc_config = (GF_HEVCConfigurationBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_HVCC);
+ entry->hevc_config->config = HEVC_DuplicateConfig(cfg);
+ entry->dataReferenceIndex = dataRefIndex;
+ e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, entry);
+ *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes);
+ HEVC_RewriteESDescriptor(entry);
+ return e;
+}
+
+GF_Err gf_isom_hevc_config_update(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_HEVCConfig *cfg)
+{
+ u32 i, array_incomplete;
+ GF_TrackBox *trak;
+ GF_Err e;
+ GF_MPEGVisualSampleEntryBox *entry;
+
+ e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
+ if (e) return e;
+ trak = gf_isom_get_track_from_file(the_file, trackNumber);
+ if (!trak || !trak->Media || !cfg || !DescriptionIndex) return GF_BAD_PARAM;
+ entry = (GF_MPEGVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, DescriptionIndex-1);
+ if (!entry) return GF_BAD_PARAM;
+ switch (entry->type) {
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
+ break;
+ default:
+ return GF_BAD_PARAM;
+ }
+
+ if (!entry->hevc_config) entry->hevc_config = (GF_HEVCConfigurationBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_HVCC);
+ if (entry->hevc_config->config) gf_odf_hevc_cfg_del(entry->hevc_config->config);
+ entry->hevc_config->config = HEVC_DuplicateConfig(cfg);
+
+ array_incomplete = 0;
+ for (i=0; ihevc_config->config->param_array); i++) {
+ GF_HEVCParamArray *ar = gf_list_get(entry->hevc_config->config->param_array, i);
+ if (!ar->array_completeness) {
+ array_incomplete = 1;
+ break;
+ }
+ }
+ entry->type = array_incomplete ? GF_ISOM_BOX_TYPE_HEV1 : GF_ISOM_BOX_TYPE_HVC1;
+
+ HEVC_RewriteESDescriptor(entry);
+ return GF_OK;
+}
+
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_EXPORT
@@ -389,13 +910,37 @@ GF_AVCConfig *gf_isom_avc_config_get(GF_ISOFile *the_file, u32 trackNumber, u32
GF_MPEGVisualSampleEntryBox *entry;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak || !trak->Media || !DescriptionIndex) return NULL;
+ if (gf_isom_get_avc_svc_type(the_file, trackNumber, DescriptionIndex)==GF_ISOM_AVCTYPE_NONE)
+ return NULL;
+
entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, DescriptionIndex-1);
if (!entry) return NULL;
- //if (entry->type != GF_ISOM_BOX_TYPE_AVC1) return NULL;
+
if (!entry->avc_config) return NULL;
return AVC_DuplicateConfig(entry->avc_config->config);
}
+GF_EXPORT
+GF_HEVCConfig *gf_isom_hevc_config_get(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
+{
+ GF_TrackBox *trak;
+ GF_MPEGVisualSampleEntryBox *entry;
+ trak = gf_isom_get_track_from_file(the_file, trackNumber);
+ if (!trak || !trak->Media || !DescriptionIndex) return NULL;
+
+ entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, DescriptionIndex-1);
+ if (!entry) return NULL;
+ switch (entry->type) {
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
+ break;
+ default:
+ return NULL;
+ }
+ if (!entry->hevc_config) return NULL;
+ return HEVC_DuplicateConfig(entry->hevc_config->config);
+}
+
GF_EXPORT
GF_AVCConfig *gf_isom_svc_config_get(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
{
@@ -403,12 +948,15 @@ GF_AVCConfig *gf_isom_svc_config_get(GF_ISOFile *the_file, u32 trackNumber, u32
GF_MPEGVisualSampleEntryBox *entry;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak || !trak->Media || !DescriptionIndex) return NULL;
+ if (gf_isom_get_avc_svc_type(the_file, trackNumber, DescriptionIndex)==GF_ISOM_AVCTYPE_NONE)
+ return NULL;
entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, DescriptionIndex-1);
if (!entry) return NULL;
if (!entry->svc_config) return NULL;
return AVC_DuplicateConfig(entry->svc_config->config);
}
+
GF_EXPORT
u32 gf_isom_get_avc_svc_type(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
{
@@ -416,11 +964,14 @@ u32 gf_isom_get_avc_svc_type(GF_ISOFile *the_file, u32 trackNumber, u32 Descript
GF_MPEGVisualSampleEntryBox *entry;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak || !trak->Media || !DescriptionIndex) return GF_ISOM_AVCTYPE_NONE;
+ if (trak->Media->handler->handlerType != GF_ISOM_MEDIA_VISUAL) return GF_ISOM_AVCTYPE_NONE;
entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, DescriptionIndex-1);
if (!entry) return GF_ISOM_AVCTYPE_NONE;
switch (entry->type) {
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
break;
default:
@@ -604,7 +1155,7 @@ GF_Err avcc_Read(GF_Box *s, GF_BitStream *bs)
AVCState avc;
s32 idx, vui_flag_pos;
GF_AVCConfigSlot *sl = gf_list_get(ptr->config->sequenceParameterSets, 0);
- idx = AVC_ReadSeqInfo(sl->data+1, sl->size-1, &avc, 0, &vui_flag_pos);
+ idx = gf_media_avc_read_sps(sl->data+1, sl->size-1, &avc, 0, &vui_flag_pos);
if (idx>=0) {
ptr->config->chroma_format = avc.sps[idx].chroma_format;
ptr->config->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8;
@@ -755,4 +1306,75 @@ GF_Err avcc_Size(GF_Box *s)
#endif /*GPAC_DISABLE_ISOM_WRITE*/
+
+void hvcc_del(GF_Box *s)
+{
+ GF_HEVCConfigurationBox *ptr = (GF_HEVCConfigurationBox*)s;
+ if (ptr->config) gf_odf_hevc_cfg_del(ptr->config);
+ gf_free(ptr);
+}
+
+GF_Err hvcc_Read(GF_Box *s, GF_BitStream *bs)
+{
+ u64 pos;
+ GF_HEVCConfigurationBox *ptr = (GF_HEVCConfigurationBox *)s;
+
+ if (ptr->config) gf_odf_hevc_cfg_del(ptr->config);
+
+ pos = gf_bs_get_position(bs);
+ ptr->config = gf_odf_hevc_cfg_read_bs(bs);
+ pos = gf_bs_get_position(bs) - pos ;
+ if (pos < ptr->size)
+ ptr->size -= (u32) pos;
+
+ return GF_OK;
+}
+GF_Box *hvcc_New()
+{
+ GF_HEVCConfigurationBox *tmp = (GF_HEVCConfigurationBox *) gf_malloc(sizeof(GF_HEVCConfigurationBox));
+ if (tmp == NULL) return NULL;
+ memset(tmp, 0, sizeof(GF_HEVCConfigurationBox));
+ tmp->type = GF_ISOM_BOX_TYPE_HVCC;
+ return (GF_Box *)tmp;
+}
+
+#ifndef GPAC_DISABLE_ISOM_WRITE
+GF_Err hvcc_Write(GF_Box *s, GF_BitStream *bs)
+{
+ GF_Err e;
+ GF_HEVCConfigurationBox *ptr = (GF_HEVCConfigurationBox *) s;
+ if (!s) return GF_BAD_PARAM;
+ if (!ptr->config) return GF_OK;
+ e = gf_isom_box_write_header(s, bs);
+ if (e) return e;
+
+ return gf_odf_hevc_cfg_write_bs(ptr->config, bs);
+}
+GF_Err hvcc_Size(GF_Box *s)
+{
+ GF_Err e;
+ u32 i, count, j, subcount;
+ GF_HEVCConfigurationBox *ptr = (GF_HEVCConfigurationBox *)s;
+ e = gf_isom_box_get_size(s);
+ if (e) return e;
+ if (!ptr->config) {
+ ptr->size = 0;
+ return e;
+ }
+ ptr->size += 16;
+
+ count = gf_list_count(ptr->config->param_array);
+ for (i=0; iconfig->param_array, i);
+ ptr->size += 3;
+ subcount = gf_list_count(ar->nalus);
+ for (j=0; jsize += 2 + ((GF_AVCConfigSlot *)gf_list_get(ar->nalus, j))->size;
+ }
+ }
+ return GF_OK;
+}
+#endif /*GPAC_DISABLE_ISOM_WRITE*/
+
+
#endif /*GPAC_DISABLE_ISOM*/
diff --git a/src/isomedia/box_code_adobe.c b/src/isomedia/box_code_adobe.c
index 32069d8..37b9820 100644
--- a/src/isomedia/box_code_adobe.c
+++ b/src/isomedia/box_code_adobe.c
@@ -25,10 +25,10 @@
*
*/
-#ifndef GPAC_DISABLE_ISOM_ADOBE
-
#include
+#ifndef GPAC_DISABLE_ISOM_ADOBE
+
#ifndef GPAC_DISABLE_ISOM
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
diff --git a/src/isomedia/box_code_base.c b/src/isomedia/box_code_base.c
index f0eec99..98e049c 100644
--- a/src/isomedia/box_code_base.c
+++ b/src/isomedia/box_code_base.c
@@ -3504,6 +3504,7 @@ void mp4v_del(GF_Box *s)
if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc);
if (ptr->avc_config) gf_isom_box_del((GF_Box *) ptr->avc_config);
if (ptr->svc_config) gf_isom_box_del((GF_Box *) ptr->svc_config);
+ if (ptr->hevc_config) gf_isom_box_del((GF_Box *) ptr->hevc_config);
if (ptr->bitrate) gf_isom_box_del((GF_Box *) ptr->bitrate);
if (ptr->descr) gf_isom_box_del((GF_Box *) ptr->descr);
if (ptr->ipod_ext) gf_isom_box_del((GF_Box *)ptr->ipod_ext);
@@ -3531,6 +3532,10 @@ GF_Err mp4v_AddBox(GF_Box *s, GF_Box *a)
if (ptr->avc_config) return GF_ISOM_INVALID_FILE;
ptr->avc_config = (GF_AVCConfigurationBox *)a;
break;
+ case GF_ISOM_BOX_TYPE_HVCC:
+ if (ptr->hevc_config) return GF_ISOM_INVALID_FILE;
+ ptr->hevc_config = (GF_HEVCConfigurationBox *)a;
+ break;
case GF_ISOM_BOX_TYPE_SVCC:
if (ptr->svc_config) return GF_ISOM_INVALID_FILE;
ptr->svc_config = (GF_AVCConfigurationBox *)a;
@@ -3571,6 +3576,8 @@ GF_Err mp4v_Read(GF_Box *s, GF_BitStream *bs)
if (e) return e;
/*this is an AVC sample desc*/
if (mp4v->avc_config || mp4v->svc_config) AVC_RewriteESDescriptor(mp4v);
+ /*this is an HEVC sample desc*/
+ if (mp4v->hevc_config ) HEVC_RewriteESDescriptor(mp4v);
return GF_OK;
}
@@ -3599,11 +3606,32 @@ GF_Box *avc2_New()
return mp4v_encv_avc1_new(GF_ISOM_BOX_TYPE_AVC2);
}
+GF_Box *avc3_New()
+{
+ return mp4v_encv_avc1_new(GF_ISOM_BOX_TYPE_AVC3);
+}
+
+GF_Box *avc4_New()
+{
+ return mp4v_encv_avc1_new(GF_ISOM_BOX_TYPE_AVC4);
+}
+
GF_Box *svc1_New()
{
return mp4v_encv_avc1_new(GF_ISOM_BOX_TYPE_SVC1);
}
+GF_Box *hvc1_New()
+{
+ return mp4v_encv_avc1_new(GF_ISOM_BOX_TYPE_HVC1);
+}
+
+GF_Box *hev1_New()
+{
+ return mp4v_encv_avc1_new(GF_ISOM_BOX_TYPE_HEV1);
+}
+
+
GF_Box *encv_New()
{
return mp4v_encv_avc1_new(GF_ISOM_BOX_TYPE_ENCV);
@@ -3636,6 +3664,10 @@ GF_Err mp4v_Write(GF_Box *s, GF_BitStream *bs)
e = gf_isom_box_write((GF_Box *) ptr->avc_config, bs);
if (e) return e;
}
+ if (ptr->hevc_config && ptr->hevc_config->config) {
+ e = gf_isom_box_write((GF_Box *) ptr->hevc_config, bs);
+ if (e) return e;
+ }
if (ptr->ipod_ext) {
e = gf_isom_box_write((GF_Box *) ptr->ipod_ext, bs);
if (e) return e;
@@ -3674,19 +3706,28 @@ GF_Err mp4v_Size(GF_Box *s)
if (e) return e;
ptr->size += ptr->esd->size;
} else {
- if (!ptr->avc_config && !ptr->svc_config)
+ if (!ptr->avc_config && !ptr->svc_config && !ptr->hevc_config) {
return GF_ISOM_INVALID_FILE;
+ }
+ if (ptr->hevc_config && ptr->hevc_config->config) {
+ e = gf_isom_box_size((GF_Box *)ptr->hevc_config);
+ if (e) return e;
+ ptr->size += ptr->hevc_config->size;
+ }
+
if (ptr->avc_config && ptr->avc_config->config) {
e = gf_isom_box_size((GF_Box *) ptr->avc_config);
if (e) return e;
ptr->size += ptr->avc_config->size;
}
+
if (ptr->svc_config && ptr->svc_config->config) {
e = gf_isom_box_size((GF_Box *) ptr->svc_config);
if (e) return e;
ptr->size += ptr->svc_config->size;
}
+
if (ptr->ipod_ext) {
e = gf_isom_box_size((GF_Box *) ptr->ipod_ext);
if (e) return e;
@@ -4902,7 +4943,11 @@ GF_Err stsd_AddBox(GF_SampleDescriptionBox *ptr, GF_Box *a)
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
case GF_ISOM_BOX_TYPE_TX3G:
case GF_ISOM_BOX_TYPE_TEXT:
case GF_ISOM_BOX_TYPE_ENCT:
@@ -6104,10 +6149,14 @@ static void gf_isom_check_sample_desc(GF_TrackBox *trak)
case GF_ISOM_SUBTYPE_3GP_H263:
case GF_ISOM_BOX_TYPE_GHNT:
case GF_ISOM_BOX_TYPE_RTP_STSD:
- case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_METX:
case GF_ISOM_BOX_TYPE_METT:
+ case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
case GF_ISOM_BOX_TYPE_SVC1:
case GF_ISOM_BOX_TYPE_TX3G:
case GF_ISOM_BOX_TYPE_TEXT:
@@ -6473,6 +6522,11 @@ GF_Err trex_Read(GF_Box *s, GF_BitStream *bs)
ptr->def_sample_duration = gf_bs_read_u32(bs);
ptr->def_sample_size = gf_bs_read_u32(bs);
ptr->def_sample_flags = gf_bs_read_u32(bs);
+
+ if (!ptr->def_sample_desc_index) {
+ GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] TREX with default sample description set to 0, likely broken ! Fixing to 1\n" ));
+ ptr->def_sample_desc_index = 1;
+ }
return GF_OK;
}
@@ -8183,7 +8237,7 @@ static void sgpd_del_entry(u32 grouping_type, void *entry)
{
GF_DefaultSampleGroupDescriptionEntry *ptr = (GF_DefaultSampleGroupDescriptionEntry *)entry;
if (ptr->data) gf_free(ptr->data);
- gf_free(ptr->data);
+ gf_free(ptr);
}
}
diff --git a/src/isomedia/box_dump.c b/src/isomedia/box_dump.c
index 9d72e92..d6560a0 100644
--- a/src/isomedia/box_dump.c
+++ b/src/isomedia/box_dump.c
@@ -305,13 +305,19 @@ GF_Err gf_box_dump(void *ptr, FILE * trace)
case GF_ISOM_BOX_TYPE_AVCC:
case GF_ISOM_BOX_TYPE_SVCC:
return avcc_dump(a, trace);
+ case GF_ISOM_BOX_TYPE_HVCC:
+ return hvcc_dump(a, trace);
case GF_ISOM_BOX_TYPE_BTRT:
return btrt_dump(a, trace);
case GF_ISOM_BOX_TYPE_M4DS:
return m4ds_dump(a, trace);
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
return mp4v_dump(a, trace);
case GF_ISOM_BOX_TYPE_PASP:
return pasp_dump(a, trace);
@@ -962,6 +968,7 @@ GF_Err mp4v_dump(GF_Box *a, FILE * trace)
if (p->esd) {
gf_box_dump(p->esd, trace);
} else {
+ if (p->hevc_config) gf_box_dump(p->hevc_config, trace);
if (p->avc_config) gf_box_dump(p->avc_config, trace);
if (p->ipod_ext) gf_box_dump(p->ipod_ext, trace);
if (p->descr) gf_box_dump(p->descr, trace);
@@ -1680,6 +1687,43 @@ GF_Err avcc_dump(GF_Box *a, FILE * trace)
return GF_OK;
}
+GF_Err hvcc_dump(GF_Box *a, FILE * trace)
+{
+ u32 i, count;
+ GF_HEVCConfigurationBox *p = (GF_HEVCConfigurationBox *) a;
+
+ fprintf(trace, "\n");
+
+ fprintf(trace, "config->nal_unit_size, p->config->configurationVersion, p->config->profile_space, p->config->profile_idc, p->config->constraint_indicator_flags);
+ fprintf(trace, "chroma_format=\"%d\" luma_bit_depth=\"%d\" chroma_bit_depth=\"%d\" avgFrameRate=\"%d\" constantFrameRate=\"%d\" numTemporalLayers=\"%d\"",
+ p->config->chromaFormat, p->config->luma_bit_depth, p->config->chroma_bit_depth, p->config->avgFrameRate, p->config->constantFrameRate, p->config->numTemporalLayers);
+
+ fprintf(trace, ">\n");
+
+ count = gf_list_count(p->config->param_array);
+ for (i=0; iconfig->param_array, i);
+ fprintf(trace, "\n", ar->type, ar->array_completeness);
+ nalucount = gf_list_count(ar->nalus);
+ for (j=0; jnalus, j);
+ fprintf(trace, "size);
+ DumpData(trace, c->data, c->size);
+ fprintf(trace, "\"/>\n");
+ }
+ fprintf(trace, "\n");
+ }
+
+ fprintf(trace, "\n");
+
+ DumpBox(a, trace);
+ gf_box_dump_done(NULL, a, trace);
+ fprintf(trace, "\n");
+ return GF_OK;
+}
+
GF_Err m4ds_dump(GF_Box *a, FILE * trace)
{
u32 i;
@@ -2299,6 +2343,19 @@ GF_Err mehd_dump(GF_Box *a, FILE * trace)
return GF_OK;
}
+void sample_flags_dump(const char *name, u32 sample_flags, FILE * trace)
+{
+ fprintf(trace, "<%s", name);
+ fprintf(trace, " IsLeading=\"%d\"", GF_ISOM_GET_FRAG_LEAD(sample_flags) );
+ fprintf(trace, " SampleDependsOn=\"%d\"", GF_ISOM_GET_FRAG_DEPENDS(sample_flags) );
+ fprintf(trace, " SampleIsDependedOn=\"%d\"", GF_ISOM_GET_FRAG_DEPENDED(sample_flags) );
+ fprintf(trace, " SampleHasRedundancy=\"%d\"", GF_ISOM_GET_FRAG_REDUNDANT(sample_flags) );
+ fprintf(trace, " SamplePadding=\"%d\"", GF_ISOM_GET_FRAG_PAD(sample_flags) );
+ fprintf(trace, " SampleSync=\"%d\"", GF_ISOM_GET_FRAG_SYNC(sample_flags));
+ fprintf(trace, " SampleDegradationPriority=\"%d\"", GF_ISOM_GET_FRAG_DEG(sample_flags));
+ fprintf(trace, "/>\n");
+}
+
GF_Err trex_dump(GF_Box *a, FILE * trace)
{
GF_TrackExtendsBox *p;
@@ -2307,10 +2364,8 @@ GF_Err trex_dump(GF_Box *a, FILE * trace)
fprintf(trace, "trackID);
fprintf(trace, " SampleDescriptionIndex=\"%d\" SampleDuration=\"%d\" SampleSize=\"%d\"", p->def_sample_desc_index, p->def_sample_duration, p->def_sample_size);
- fprintf(trace, " SamplePadding=\"%d\" SampleSync=\"%d\" SampleDegradationPriority=\"%d\"",
- GF_ISOM_GET_FRAG_PAD(p->def_sample_flags), GF_ISOM_GET_FRAG_SYNC(p->def_sample_flags), GF_ISOM_GET_FRAG_DEG(p->def_sample_flags));
-
fprintf(trace, ">\n");
+ sample_flags_dump("DefaultSampleFlags", p->def_sample_flags, trace);
DumpBox(a, trace);
gf_full_box_dump(a, trace);
gf_box_dump_done("TrackExtendsBox", a, trace);
@@ -2402,10 +2457,11 @@ GF_Err trun_dump(GF_Box *a, FILE * trace)
if (p->flags & GF_ISOM_TRUN_DATA_OFFSET)
fprintf(trace, " DataOffset=\"%d\"", p->data_offset);
+ fprintf(trace, ">\n");
+
if (p->flags & GF_ISOM_TRUN_FIRST_FLAG) {
- fprintf(trace, " FirstSamplePadding=\"%d\" FirstSampleSync=\"%d\" FirstSampleDegradationPriority=\"%d\"", GF_ISOM_GET_FRAG_PAD(p->first_sample_flags), GF_ISOM_GET_FRAG_SYNC(p->first_sample_flags), GF_ISOM_GET_FRAG_DEG(p->first_sample_flags));
+ sample_flags_dump("FirstSampleFlags", p->first_sample_flags, trace);
}
- fprintf(trace, ">\n");
DumpBox(a, trace);
gf_full_box_dump(a, trace);
diff --git a/src/isomedia/box_funcs.c b/src/isomedia/box_funcs.c
index ac7c774..1daaf79 100644
--- a/src/isomedia/box_funcs.c
+++ b/src/isomedia/box_funcs.c
@@ -501,12 +501,18 @@ GF_Box *gf_isom_box_new(u32 boxType)
a = avcc_New();
if (a) a->type = boxType;
return a;
+ case GF_ISOM_BOX_TYPE_HVCC:
+ return hvcc_New();
case GF_ISOM_BOX_TYPE_BTRT: return btrt_New();
case GF_ISOM_BOX_TYPE_M4DS: return m4ds_New();
case GF_ISOM_BOX_TYPE_AVC1: return avc1_New();
case GF_ISOM_BOX_TYPE_AVC2: return avc2_New();
+ case GF_ISOM_BOX_TYPE_AVC3: return avc3_New();
+ case GF_ISOM_BOX_TYPE_AVC4: return avc4_New();
case GF_ISOM_BOX_TYPE_SVC1: return svc1_New();
+ case GF_ISOM_BOX_TYPE_HVC1: return hvc1_New();
+ case GF_ISOM_BOX_TYPE_HEV1: return hev1_New();
/*3GPP streaming text*/
case GF_ISOM_BOX_TYPE_FTAB: return ftab_New();
@@ -795,8 +801,13 @@ void gf_isom_box_del(GF_Box *a)
case GF_ISOM_BOX_TYPE_M4DS: m4ds_del(a); return;
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
mp4v_del(a); return;
+ case GF_ISOM_BOX_TYPE_HVCC: hvcc_del(a); return;
/*3GPP streaming text*/
case GF_ISOM_BOX_TYPE_FTAB: ftab_del(a); return;
@@ -1066,8 +1077,14 @@ GF_Err gf_isom_box_read(GF_Box *a, GF_BitStream *bs)
case GF_ISOM_BOX_TYPE_M4DS: return m4ds_Read(a, bs);
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
return mp4v_Read(a, bs);
+ case GF_ISOM_BOX_TYPE_HVCC:
+ return hvcc_Read(a, bs);
/*3GPP streaming text*/
case GF_ISOM_BOX_TYPE_FTAB: return ftab_Read(a, bs);
@@ -1319,11 +1336,17 @@ GF_Err gf_isom_box_write_listing(GF_Box *a, GF_BitStream *bs)
case GF_ISOM_BOX_TYPE_AVCC:
case GF_ISOM_BOX_TYPE_SVCC:
return avcc_Write(a, bs);
+ case GF_ISOM_BOX_TYPE_HVCC:
+ return hvcc_Write(a, bs);
case GF_ISOM_BOX_TYPE_BTRT: return btrt_Write(a, bs);
case GF_ISOM_BOX_TYPE_M4DS: return m4ds_Write(a, bs);
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
return mp4v_Write(a, bs);
/*3GPP streaming text*/
@@ -1584,11 +1607,17 @@ static GF_Err gf_isom_box_size_listing(GF_Box *a)
case GF_ISOM_BOX_TYPE_AVCC:
case GF_ISOM_BOX_TYPE_SVCC:
return avcc_Size(a);
+ case GF_ISOM_BOX_TYPE_HVCC:
+ return hvcc_Size(a);
case GF_ISOM_BOX_TYPE_BTRT: return btrt_Size(a);
case GF_ISOM_BOX_TYPE_M4DS: return m4ds_Size(a);
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
return mp4v_Size(a);
/*3GPP streaming text*/
diff --git a/src/isomedia/data_map.c b/src/isomedia/data_map.c
index 68bc03c..298c3cb 100644
--- a/src/isomedia/data_map.c
+++ b/src/isomedia/data_map.c
@@ -130,6 +130,10 @@ GF_Err gf_isom_datamap_new(const char *location, const char *parentPath, u8 mode
#else
return GF_NOT_SUPPORTED;
#endif
+ } else if (!strncmp(location, "gmem://", 7)) {
+ *outDataMap = gf_isom_fdm_new(location, GF_ISOM_DATA_MAP_READ);
+ if (! (*outDataMap)) return GF_IO_ERR;
+ return GF_OK;
}
extern_file = !gf_url_is_local(location);
@@ -340,6 +344,18 @@ GF_DataMap *gf_isom_fdm_new(const char *sPath, u8 mode)
bs_mode = GF_BITSTREAM_READ;
}
#endif
+ if (!strncmp(sPath, "gmem://", 7)) {
+ u32 size;
+ void *mem_address;
+ if (sscanf(sPath, "gmem://%d@%p", &size, &mem_address) != 2)
+ return NULL;
+ tmp->bs = gf_bs_new((const char *)mem_address, size, GF_BITSTREAM_READ);
+ if (!tmp->bs) {
+ gf_free(tmp);
+ return NULL;
+ }
+ return (GF_DataMap *)tmp;
+ }
switch (mode) {
case GF_ISOM_DATA_MAP_READ:
@@ -426,7 +442,7 @@ u32 gf_isom_fdm_get_data(GF_FileDataMap *ptr, char *buffer, u32 bufferLength, u6
//rewind to original (if seek fails, return 0 cause this means:
//1- no support for seek on the platform
//2- corrupted file for the OS
- fflush(ptr->stream);
+ if (ptr->stream) fflush(ptr->stream);
gf_bs_seek(ptr->bs, ptr->curPos);
}
ptr->last_acces_was_read = 1;
@@ -472,7 +488,7 @@ GF_Err FDM_AddData(GF_FileDataMap *ptr, char *data, u32 dataSize)
}
ptr->curPos = gf_bs_get_position(ptr->bs);
//flush the stream !!
- fflush(ptr->stream);
+ if (ptr->stream) fflush(ptr->stream);
return GF_OK;
}
diff --git a/src/isomedia/drm_sample.c b/src/isomedia/drm_sample.c
index f94ed33..1bf6093 100644
--- a/src/isomedia/drm_sample.c
+++ b/src/isomedia/drm_sample.c
@@ -337,6 +337,7 @@ GF_Err gf_isom_remove_ismacryp_protection(GF_ISOFile *the_file, u32 trackNumber,
gf_isom_box_array_del(sea->protections);
sea->protections = gf_list_new();
if (sea->type == GF_4CC('2','6','4','b')) sea->type = GF_ISOM_BOX_TYPE_AVC1;
+ if (sea->type == GF_4CC('2','6','5','b')) sea->type = GF_ISOM_BOX_TYPE_HVC1;
return GF_OK;
}
@@ -403,10 +404,17 @@ GF_Err gf_isom_set_ismacryp_protection(GF_ISOFile *the_file, u32 trackNumber, u3
/*special case for AVC1*/
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
original_format = GF_4CC('2','6','4','b');
sea->type = GF_ISOM_BOX_TYPE_ENCV;
break;
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
+ original_format = GF_4CC('2','6','5','b');
+ sea->type = GF_ISOM_BOX_TYPE_ENCV;
+ break;
case GF_ISOM_BOX_TYPE_MP4S:
case GF_ISOM_BOX_TYPE_LSR1:
original_format = sea->type;
@@ -467,8 +475,12 @@ GF_Err gf_isom_set_oma_protection(GF_ISOFile *the_file, u32 trackNumber, u32 des
case GF_ISOM_BOX_TYPE_MP4V:
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
case GF_ISOM_BOX_TYPE_D263:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
original_format = sea->type;
sea->type = GF_ISOM_BOX_TYPE_ENCV;
break;
diff --git a/src/isomedia/isom_intern.c b/src/isomedia/isom_intern.c
index 6d54c1f..30bf769 100644
--- a/src/isomedia/isom_intern.c
+++ b/src/isomedia/isom_intern.c
@@ -481,6 +481,20 @@ GF_TrackBox *gf_isom_get_track_from_id(GF_MovieBox *moov, u32 trackID)
return NULL;
}
+GF_TrackBox *gf_isom_get_track_from_original_id(GF_MovieBox *moov, u32 originalID, u32 originalFile)
+{
+ u32 i, count;
+ GF_TrackBox *trak;
+ if (!moov || !originalID) return NULL;
+
+ count = gf_list_count(moov->trackList);
+ for (i = 0; itrackList, i);
+ if ((trak->originalFile == originalFile) && (trak->originalID == originalID)) return trak;
+ }
+ return NULL;
+}
+
GF_TrackBox *gf_isom_get_track_from_file(GF_ISOFile *movie, u32 trackNumber)
{
GF_TrackBox *trak;
diff --git a/src/isomedia/isom_read.c b/src/isomedia/isom_read.c
index 8638353..5297372 100644
--- a/src/isomedia/isom_read.c
+++ b/src/isomedia/isom_read.c
@@ -92,17 +92,28 @@ void gf_isom_sample_del(GF_ISOSample **samp)
GF_EXPORT
Bool gf_isom_probe_file(const char *fileName)
{
- unsigned char data[4];
- u32 type;
- FILE *f = gf_f64_open(fileName, "rb");
- if (!f) return 0;
- type = 0;
- if (fread(data, 1, 4, f) == 4) {
+ u32 type = 0;
+
+ if (!strncmp(fileName, "gmem://", 7)) {
+ u32 size;
+ u8 *mem_address;
+ if (sscanf(fileName, "gmem://%d@%p", &size, &mem_address) != 2) {
+ return GF_URL_ERROR;
+ }
+ if (size>8)
+ type = GF_4CC(mem_address[4], mem_address[5], mem_address[6], mem_address[7]);
+ } else {
+ unsigned char data[4];
+ FILE *f = gf_f64_open(fileName, "rb");
+ if (!f) return 0;
+ type = 0;
if (fread(data, 1, 4, f) == 4) {
- type = GF_4CC(data[0], data[1], data[2], data[3]);
+ if (fread(data, 1, 4, f) == 4) {
+ type = GF_4CC(data[0], data[1], data[2], data[3]);
+ }
}
+ fclose(f);
}
- fclose(f);
switch (type) {
case GF_ISOM_BOX_TYPE_MOOV:
case GF_ISOM_BOX_TYPE_MDAT:
@@ -405,6 +416,16 @@ u32 gf_isom_get_track_by_id(GF_ISOFile *the_file, u32 trackID)
return 0;
}
+GF_EXPORT
+u32 gf_isom_get_track_original_id(GF_ISOFile *movie, u32 trackNumber)
+{
+ GF_TrackBox *trak;
+ if (!movie) return 0;
+ trak = gf_isom_get_track_from_file(movie, trackNumber);
+ if (!trak) return 0;
+ return trak->originalID;
+}
+
//return the timescale of the movie, 0 if error
GF_EXPORT
Bool gf_isom_has_movie(GF_ISOFile *file)
@@ -568,7 +589,7 @@ GF_Err gf_isom_get_media_language(GF_ISOFile *the_file, u32 trackNumber, char *t
//Return the number of track references of a track for a given ReferenceType
-//return -1 if error
+//return 0 if error
GF_EXPORT
s32 gf_isom_get_reference_count(GF_ISOFile *movie, u32 trackNumber, u32 referenceType)
{
@@ -622,10 +643,35 @@ GF_Err gf_isom_get_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceTy
return GF_OK;
}
-//Return the number of track references of a track for a given ReferenceType
+//Return the referenced track ID for a track and a given ReferenceType and Index
+//return -1 if error, 0 if the reference is a NULL one, or the trackNumber
+GF_EXPORT
+GF_Err gf_isom_get_reference_ID(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 referenceIndex, u32 *refTrackID)
+{
+ GF_Err e;
+ GF_TrackBox *trak;
+ GF_TrackReferenceTypeBox *dpnd;
+ trak = gf_isom_get_track_from_file(movie, trackNumber);
+
+ *refTrackID = 0;
+ if (!trak || !trak->References) return GF_BAD_PARAM;
+
+ dpnd = NULL;
+ e = Track_FindRef(trak, referenceType, &dpnd);
+ if (e) return e;
+ if (!dpnd) return GF_BAD_PARAM;
+
+ if (referenceIndex > dpnd->trackIDCount) return GF_BAD_PARAM;
+
+ *refTrackID = dpnd->trackIDs[referenceIndex-1];
+
+ return GF_OK;
+}
+
+//Return referenceIndex if the given track has a reference to the given TreckID of a given ReferenceType
//return -1 if error
GF_EXPORT
-Bool gf_isom_has_track_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 refTrackID)
+u32 gf_isom_has_track_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 refTrackID)
{
u32 i;
GF_TrackBox *trak;
@@ -638,7 +684,7 @@ Bool gf_isom_has_track_reference(GF_ISOFile *movie, u32 trackNumber, u32 referen
if ( (movie->LastError = Track_FindRef(trak, referenceType, &dpnd)) ) return 0;
if (!dpnd) return 0;
for (i=0; itrackIDCount; i++) {
- if (dpnd->trackIDs[i]==refTrackID) return 1;
+ if (dpnd->trackIDs[i]==refTrackID) return i+1;
}
return 0;
}
@@ -2162,8 +2208,12 @@ GF_Err gf_isom_get_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDes
case GF_ISOM_SUBTYPE_3GP_H263:
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
case GF_ISOM_BOX_TYPE_GNRV:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
*Width = ((GF_VisualSampleEntryBox*)entry)->Width;
*Height = ((GF_VisualSampleEntryBox*)entry)->Height;
return GF_OK;
@@ -2238,8 +2288,12 @@ GF_Err gf_isom_get_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 St
case GF_ISOM_SUBTYPE_3GP_H263:
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
case GF_ISOM_BOX_TYPE_GNRV:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
*hSpacing = ((GF_VisualSampleEntryBox*)entry)->pasp ? ((GF_VisualSampleEntryBox*)entry)->pasp->hSpacing : 0;
*vSpacing = ((GF_VisualSampleEntryBox*)entry)->pasp ? ((GF_VisualSampleEntryBox*)entry)->pasp->vSpacing : 0;
return GF_OK;
@@ -2417,8 +2471,12 @@ u32 gf_isom_guess_specification(GF_ISOFile *file)
case GF_ISOM_SUBTYPE_3GP_EVRC: nb_evrc++; break;
case GF_ISOM_SUBTYPE_3GP_QCELP: nb_qcelp++; break;
case GF_ISOM_SUBTYPE_3GP_SMV: nb_smv++; break;
- case GF_ISOM_SUBTYPE_AVC_H264: nb_avc++; break;
- case GF_ISOM_SUBTYPE_AVC2_H264: nb_avc++; break;
+ case GF_ISOM_SUBTYPE_AVC_H264:
+ case GF_ISOM_SUBTYPE_AVC2_H264:
+ case GF_ISOM_SUBTYPE_AVC3_H264:
+ case GF_ISOM_SUBTYPE_AVC4_H264:
+ nb_avc++;
+ break;
case GF_ISOM_SUBTYPE_SVC_H264: nb_avc++; break;
case GF_ISOM_SUBTYPE_MPEG4:
case GF_ISOM_SUBTYPE_MPEG4_CRYP:
@@ -2681,8 +2739,12 @@ GF_Err gf_isom_get_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptio
case GF_ISOM_BOX_TYPE_MP4V:
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
case GF_ISOM_BOX_TYPE_ENCV:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
break;
default:
return GF_BAD_PARAM;
@@ -2845,4 +2907,30 @@ u32 gf_isom_get_fragments_count(GF_ISOFile *movie, Bool segments_only)
#endif
+GF_EXPORT
+GF_Err gf_isom_set_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber, u32 nalu_extract_mode)
+{
+ GF_TrackReferenceTypeBox *dpnd;
+ GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
+ if (!trak) return GF_BAD_PARAM;
+ trak->extractor_mode = nalu_extract_mode;
+
+ if (!trak->References) return GF_OK;
+
+ /*get base*/
+ dpnd = NULL;
+ trak->has_base_layer = 0;
+ Track_FindRef(trak, GF_ISOM_REF_SCAL, &dpnd);
+ if (dpnd) trak->has_base_layer = 1;
+ return GF_OK;
+}
+
+GF_EXPORT
+u32 gf_isom_get_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber)
+{
+ GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
+ if (!trak) return 0;
+ return trak->extractor_mode;
+}
+
#endif /*GPAC_DISABLE_ISOM*/
diff --git a/src/isomedia/isom_write.c b/src/isomedia/isom_write.c
index f94d4df..587f9c0 100644
--- a/src/isomedia/isom_write.c
+++ b/src/isomedia/isom_write.c
@@ -1171,7 +1171,11 @@ GF_Err gf_isom_set_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDes
case GF_ISOM_SUBTYPE_3GP_H263:
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
((GF_VisualSampleEntryBox*)entry)->Width = Width;
((GF_VisualSampleEntryBox*)entry)->Height = Height;
trak->Header->width = Width<<16;
@@ -1215,7 +1219,11 @@ GF_Err gf_isom_set_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 St
case GF_ISOM_SUBTYPE_3GP_H263:
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
break;
default:
return GF_BAD_PARAM;
@@ -2451,6 +2459,7 @@ GF_Err gf_isom_clone_track(GF_ISOFile *orig_file, u32 orig_track, GF_ISOFile *de
GF_TrackBox *trak, *new_tk;
GF_BitStream *bs;
char *data;
+ const char *buffer;
u32 data_size;
Double ts_scale;
GF_Err e;
@@ -2510,6 +2519,12 @@ GF_Err gf_isom_clone_track(GF_ISOFile *orig_file, u32 orig_track, GF_ISOFile *de
moov_AddBox((GF_Box*)dest_file->moov, (GF_Box *)new_tk);
+ /*set originalID*/
+ new_tk->originalID = trak->Header->trackID;
+ /*set originalFile*/
+ buffer = gf_isom_get_filename(orig_file);
+ new_tk->originalFile = gf_crc_32(buffer, sizeof(buffer));
+
/*rewrite edit list segmentDuration to new movie timescale*/
ts_scale = dest_file->moov->mvhd->timeScale;
ts_scale /= orig_file->moov->mvhd->timeScale;
@@ -2974,6 +2989,36 @@ GF_Err gf_isom_set_track_id(GF_ISOFile *movie, u32 trackNumber, u32 trackID)
return GF_OK;
}
+/*force to rewrite all dependencies when the trackID of referenced track changes*/
+GF_EXPORT
+GF_Err gf_isom_rewrite_track_dependencies(GF_ISOFile *movie, u32 trackNumber)
+{
+ GF_TrackReferenceTypeBox *ref;
+ GF_TrackBox *trak, *a_trak;
+ u32 i, k;
+
+ trak = gf_isom_get_track_from_file(movie, trackNumber);
+ if (!trak)
+ return GF_BAD_PARAM;
+ if (!trak->References)
+ return GF_OK;
+
+ i=0;
+ while ((ref = (GF_TrackReferenceTypeBox *)gf_list_enum(trak->References->other_boxes, &i))) {
+ for (k=0; k < ref->trackIDCount; k++) {
+ a_trak = gf_isom_get_track_from_original_id(movie->moov, ref->trackIDs[k], trak->originalFile);
+ if (a_trak) {
+ ref->trackIDs[k] = a_trak->Header->trackID;
+ } else {
+ a_trak = gf_isom_get_track_from_id(movie->moov, ref->trackIDs[k]);
+ /*we should have a track with no original ID (not imported) - should we rewrite the dependency ?*/
+ if (! a_trak || a_trak->originalID) return GF_BAD_PARAM;
+ }
+ }
+ }
+
+ return GF_OK;
+}
GF_EXPORT
GF_Err gf_isom_modify_cts_offset(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, u32 offset)
@@ -3259,21 +3304,25 @@ Bool gf_isom_is_same_sample_description(GF_ISOFile *f1, u32 tk1, u32 sdesc_index
break;
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
{
GF_MPEGVisualSampleEntryBox *avc1 = (GF_MPEGVisualSampleEntryBox *)ent1;
GF_MPEGVisualSampleEntryBox *avc2 = (GF_MPEGVisualSampleEntryBox *)ent2;
data1 = data2 = NULL;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
- a = (GF_Box *)avc1->avc_config;
+ a = avc1->hevc_config ? (GF_Box *) avc1->hevc_config : (GF_Box *) avc1->avc_config;
gf_isom_box_size(a);
gf_isom_box_write(a, bs);
gf_bs_get_content(bs, &data1, &data1_size);
gf_bs_del(bs);
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
- a = (GF_Box *)avc2->avc_config;
+ a = avc2->hevc_config ? (GF_Box *) avc2->hevc_config : (GF_Box *) avc2->avc_config;
gf_isom_box_size(a);
gf_isom_box_write(a, bs);
gf_bs_get_content(bs, &data2, &data2_size);
@@ -4100,8 +4149,12 @@ GF_Err gf_isom_set_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptio
case GF_ISOM_BOX_TYPE_MP4V:
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
case GF_ISOM_BOX_TYPE_ENCV:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
break;
default:
return GF_BAD_PARAM;
@@ -4410,7 +4463,6 @@ GF_Err gf_isom_set_composition_offset_mode(GF_ISOFile *file, u32 track, Bool use
}
}
-
#endif /*!defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)*/
diff --git a/src/isomedia/media.c b/src/isomedia/media.c
index 24a6d20..1aa4762 100644
--- a/src/isomedia/media.c
+++ b/src/isomedia/media.c
@@ -173,7 +173,11 @@ GF_Err Media_GetESD(GF_MediaBox *mdia, u32 sampleDescIndex, GF_ESD **out_esd, Bo
break;
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd;
break;
case GF_ISOM_BOX_TYPE_MP4A:
@@ -373,6 +377,10 @@ GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp,
e = Media_RewriteODFrame(mdia, *samp);
if (e) return e;
}
+ else if (gf_isom_is_nalu_based_entry(mdia, entry)) {
+ e = gf_isom_nalu_sample_rewrite(mdia, *samp, sampleNumber, (GF_MPEGVisualSampleEntryBox *)entry);
+ if (e) return e;
+ }
else if (mdia->mediaTrack->moov->mov->convert_streaming_text
&& ((mdia->handler->handlerType == GF_ISOM_MEDIA_TEXT) || (mdia->handler->handlerType == GF_ISOM_MEDIA_SUBT))
) {
diff --git a/src/isomedia/movie_fragments.c b/src/isomedia/movie_fragments.c
index 02c44c0..bf45801 100644
--- a/src/isomedia/movie_fragments.c
+++ b/src/isomedia/movie_fragments.c
@@ -883,7 +883,7 @@ GF_Err gf_isom_allocate_sidx(GF_ISOFile *movie, s32 subsegs_per_sidx, Bool daisy
if (e) return e;
if (start_range) *start_range = (u32) movie->root_sidx_offset;
- if (end_range) *end_range = (u32) gf_bs_get_position(bs);
+ if (end_range) *end_range = (u32) gf_bs_get_position(bs)-1;
return GF_OK;
}
diff --git a/src/isomedia/stbl_write.c b/src/isomedia/stbl_write.c
index aee50e5..90d75df 100644
--- a/src/isomedia/stbl_write.c
+++ b/src/isomedia/stbl_write.c
@@ -78,7 +78,10 @@ GF_Err stbl_AddDTS(GF_SampleTableBox *stbl, u64 DTS, u32 *sampleNumber, u32 Last
//we need to split the entry
if (ent->sampleCount == 1) {
//use this one and adjust...
- ent->sampleDelta = (u32) (DTS - stts->w_LastDTS);
+ if (stts->w_LastDTS)
+ ent->sampleDelta += (u32) (DTS - stts->w_LastDTS);
+ else
+ ent->sampleDelta = (u32) DTS;
ent->sampleCount ++;
stts->w_currentSampleNum ++;
stts->w_LastDTS = DTS;
diff --git a/src/isomedia/track.c b/src/isomedia/track.c
index b8b02de..507b7e9 100644
--- a/src/isomedia/track.c
+++ b/src/isomedia/track.c
@@ -197,7 +197,7 @@ default_sync:
} else {
esd->decoderConfig->rvc_config = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
if (mime_type && !strcmp(mime_type, "application/rvc-config+xml+gz") ) {
-#ifndef GPAC_DISABLE_CORE_TOOLS
+#if !defined(GPAC_DISABLE_CORE_TOOLS) && !defined(GPAC_DISABLE_ZLIB)
gf_gz_decompress_payload(rvc_cfg_data, rvc_cfg_size, &esd->decoderConfig->rvc_config->data, &esd->decoderConfig->rvc_config->dataLength);
gf_free(rvc_cfg_data);
#endif
@@ -877,8 +877,12 @@ GF_Err Track_SetStreamDescriptor(GF_TrackBox *trak, u32 StreamDescriptionIndex,
break;
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
+ case GF_ISOM_BOX_TYPE_AVC3:
+ case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
- e = AVC_UpdateESD((GF_MPEGVisualSampleEntryBox*)entry, esd);
+ case GF_ISOM_BOX_TYPE_HVC1:
+ case GF_ISOM_BOX_TYPE_HEV1:
+ e = AVC_HEVC_UpdateESD((GF_MPEGVisualSampleEntryBox*)entry, esd);
if (e) return e;
break;
case GF_ISOM_BOX_TYPE_LSR1:
@@ -887,7 +891,7 @@ GF_Err Track_SetStreamDescriptor(GF_TrackBox *trak, u32 StreamDescriptionIndex,
break;
default:
- gf_odf_desc_del((GF_Descriptor *) esd);
+ //gf_odf_desc_del((GF_Descriptor *) esd);
break;
}
} else {
@@ -905,7 +909,12 @@ GF_Err Track_SetStreamDescriptor(GF_TrackBox *trak, u32 StreamDescriptionIndex,
if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_AVC) {
entry_v = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_AVC1);
if (!entry_v) return GF_OUT_OF_MEM;
- e = AVC_UpdateESD((GF_MPEGVisualSampleEntryBox*)entry_v, esd);
+ e = AVC_HEVC_UpdateESD((GF_MPEGVisualSampleEntryBox*)entry_v, esd);
+ } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_HEVC) {
+ entry_v = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_HVC1);
+ if (!entry_v) return GF_OUT_OF_MEM;
+ e = AVC_HEVC_UpdateESD((GF_MPEGVisualSampleEntryBox*)entry_v, esd);
+
} else {
entry_v = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MP4V);
if (!entry_v) return GF_OUT_OF_MEM;
diff --git a/src/media_tools/av_parsers.c b/src/media_tools/av_parsers.c
index d54f1d6..74bc079 100644
--- a/src/media_tools/av_parsers.c
+++ b/src/media_tools/av_parsers.c
@@ -1461,7 +1461,7 @@ static u8 avc_golomb_bits[256] = {
0
};
-static u32 avc_get_ue(GF_BitStream *bs)
+static u32 bs_get_ue(GF_BitStream *bs)
{
u8 coded;
u32 bits = 0, read = 0;
@@ -1478,14 +1478,14 @@ static u32 avc_get_ue(GF_BitStream *bs)
return gf_bs_read_int(bs, bits + 1) - 1;
}
-static s32 avc_get_se(GF_BitStream *bs)
+static s32 bs_get_se(GF_BitStream *bs)
{
- u32 v = avc_get_ue(bs);
+ u32 v = bs_get_ue(bs);
if ((v & 0x1) == 0) return (s32) (0 - (v>>1));
return (v + 1) >> 1;
}
-u32 AVC_IsStartCode(GF_BitStream *bs)
+u32 gf_media_nalu_is_start_code(GF_BitStream *bs)
{
u8 s1, s2, s3, s4;
Bool is_sc = 0;
@@ -1506,7 +1506,7 @@ u32 AVC_IsStartCode(GF_BitStream *bs)
/*read that amount of data at each IO access rather than fetching byte by byte...*/
#define AVC_CACHE_SIZE 4096
-u32 AVC_NextStartCode(GF_BitStream *bs)
+u32 gf_media_nalu_next_start_code_bs(GF_BitStream *bs)
{
u32 v, bpos;
char avc_cache[AVC_CACHE_SIZE];
@@ -1539,7 +1539,37 @@ u32 AVC_NextStartCode(GF_BitStream *bs)
return (u32) (end-start);
}
-Bool AVC_SliceIsIntra(AVCState *avc)
+u32 gf_media_nalu_next_start_code(u8 *data, u32 data_len, u32 *sc_size)
+{
+ u32 v, bpos;
+ u32 end;
+
+ bpos = 0;
+ end = 0;
+ v = 0xffffffff;
+ while (!end) {
+ /*refill cache*/
+ if (bpos == (u32) data_len)
+ break;
+
+ v = ( (v<<8) & 0xFFFFFF00) | ((u32) data[bpos]);
+ bpos++;
+ if (v == 0x00000001) {
+ end = bpos-4;
+ *sc_size = 4;
+ return end;
+ }
+ else if ( (v & 0x00FFFFFF) == 0x00000001) {
+ end = bpos-3;
+ *sc_size = 3;
+ return end;
+ }
+ }
+ if (!end) end = data_len;
+ return (u32) (end);
+}
+
+Bool gf_media_avc_slice_is_intra(AVCState *avc)
{
switch (avc->s_info.slice_type) {
case GF_AVC_TYPE_I:
@@ -1552,7 +1582,7 @@ Bool AVC_SliceIsIntra(AVCState *avc)
}
}
-Bool AVC_SliceIsIDR(AVCState *avc)
+Bool gf_media_avc_slice_is_IDR(AVCState *avc)
{
if (avc->sei.recovery_point.valid)
{
@@ -1561,7 +1591,7 @@ Bool AVC_SliceIsIDR(AVCState *avc)
}
if (avc->s_info.nal_unit_type != GF_AVC_NALU_IDR_SLICE)
return 0;
- return AVC_SliceIsIntra(avc);
+ return gf_media_avc_slice_is_intra(avc);
}
static const struct { u32 w, h; } avc_sar[14] =
@@ -1578,14 +1608,16 @@ static void avc_parse_hrd_parameters(GF_BitStream *bs, AVC_HRD *hrd)
{
int i, cpb_cnt_minus1;
- cpb_cnt_minus1 = avc_get_ue(bs); /*cpb_cnt_minus1*/
+ cpb_cnt_minus1 = bs_get_ue(bs); /*cpb_cnt_minus1*/
+ if (cpb_cnt_minus1 > 31)
+ GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[avc-h264] invalid cpb_cnt_minus1 value: %d (expected in [0;31])\n", cpb_cnt_minus1));
gf_bs_read_int(bs, 4); /*bit_rate_scale*/
gf_bs_read_int(bs, 4); /*cpb_size_scale*/
/*for( SchedSelIdx = 0; SchedSelIdx <= cpb_cnt_minus1; SchedSelIdx++ ) {*/
for (i=0; i<=cpb_cnt_minus1; i++) {
- avc_get_ue(bs); /*bit_rate_value_minus1[ SchedSelIdx ]*/
- avc_get_ue(bs); /*cpb_size_value_minus1[ SchedSelIdx ]*/
+ bs_get_ue(bs); /*bit_rate_value_minus1[ SchedSelIdx ]*/
+ bs_get_ue(bs); /*cpb_size_value_minus1[ SchedSelIdx ]*/
gf_bs_read_int(bs, 1); /*cbr_flag[ SchedSelIdx ]*/
}
gf_bs_read_int(bs, 5); /*initial_cpb_removal_delay_length_minus1*/
@@ -1733,7 +1765,7 @@ static u32 avc_remove_emulation_bytes(const unsigned char *buffer_src, unsigned
return nal_size-emulation_bytes_count;
}
-s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps, u32 *vui_flag_pos)
+s32 gf_media_avc_read_sps(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps, u32 *vui_flag_pos)
{
AVC_SPS *sps;
u32 ChromaArrayType = 0;
@@ -1753,6 +1785,8 @@ s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps,
}
if (vui_flag_pos) *vui_flag_pos = 0;
+ /*nal hdr*/ gf_bs_read_int(bs, 8);
+
profile_idc = gf_bs_read_int(bs, 8);
pcomp = gf_bs_read_int(bs, 8);
@@ -1765,7 +1799,7 @@ s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps,
/*SubsetSps is used to be sure that AVC SPS are not going to be scratched
by subset SPS. According to the SVC standard, subset SPS can have the same sps_id
than its base layer, but it does not refer to the same SPS. */
- sps_id = avc_get_ue(bs) + GF_SVC_SSPS_ID_SHIFT * subseq_sps;
+ sps_id = bs_get_ue(bs) + GF_SVC_SSPS_ID_SHIFT * subseq_sps;
if (sps_id >=32) {
sps_id = -1;
goto exit;
@@ -1789,7 +1823,7 @@ s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps,
case 86:
case 118:
case 128:
- chroma_format_idc = avc_get_ue(bs);
+ chroma_format_idc = bs_get_ue(bs);
ChromaArrayType = chroma_format_idc;
if (chroma_format_idc == 3) {
u8 separate_colour_plane_flag = gf_bs_read_int(bs, 1);
@@ -1800,8 +1834,8 @@ s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps,
*/
if (separate_colour_plane_flag) ChromaArrayType = 0;
}
- luma_bd = avc_get_ue(bs);
- chroma_bd = avc_get_ue(bs);
+ luma_bd = bs_get_ue(bs);
+ chroma_bd = bs_get_ue(bs);
/*qpprime_y_zero_transform_bypass_flag = */ gf_bs_read_int(bs, 1);
/*seq_scaling_matrix_present_flag*/
if (gf_bs_read_int(bs, 1)) {
@@ -1812,7 +1846,7 @@ s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps,
u32 sl = k<6 ? 16 : 64;
for (z=0; zprofile_idc = profile_idc;
sps->level_idc = level_idc;
sps->prof_compat = pcomp;
- sps->log2_max_frame_num = avc_get_ue(bs) + 4;
- sps->poc_type = avc_get_ue(bs);
+ sps->log2_max_frame_num = bs_get_ue(bs) + 4;
+ sps->poc_type = bs_get_ue(bs);
sps->chroma_format = chroma_format_idc;
sps->luma_bit_depth_m8 = luma_bd;
sps->chroma_bit_depth_m8 = chroma_bd;
if (sps->poc_type == 0) {
- sps->log2_max_poc_lsb = avc_get_ue(bs) + 4;
+ sps->log2_max_poc_lsb = bs_get_ue(bs) + 4;
} else if(sps->poc_type == 1) {
sps->delta_pic_order_always_zero_flag = gf_bs_read_int(bs, 1);
- sps->offset_for_non_ref_pic = avc_get_se(bs);
- sps->offset_for_top_to_bottom_field = avc_get_se(bs);
- sps->poc_cycle_length = avc_get_ue(bs);
- for(i=0; ipoc_cycle_length; i++) sps->offset_for_ref_frame[i] = avc_get_se(bs);
+ sps->offset_for_non_ref_pic = bs_get_se(bs);
+ sps->offset_for_top_to_bottom_field = bs_get_se(bs);
+ sps->poc_cycle_length = bs_get_ue(bs);
+ for(i=0; ipoc_cycle_length; i++) sps->offset_for_ref_frame[i] = bs_get_se(bs);
}
if (sps->poc_type > 2) {
sps_id = -1;
goto exit;
}
- avc_get_ue(bs); /*ref_frame_count*/
+ bs_get_ue(bs); /*ref_frame_count*/
gf_bs_read_int(bs, 1); /*gaps_in_frame_num_allowed_flag*/
- mb_width = avc_get_ue(bs) + 1;
- mb_height= avc_get_ue(bs) + 1;
+ mb_width = bs_get_ue(bs) + 1;
+ mb_height= bs_get_ue(bs) + 1;
sps->frame_mbs_only_flag = gf_bs_read_int(bs, 1);
@@ -1860,10 +1894,10 @@ s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps,
gf_bs_read_int(bs, 1); /*direct_8x8_inference_flag*/
cl = cr = ct = cb = 0;
if (gf_bs_read_int(bs, 1)) /*crop*/ {
- cl = avc_get_ue(bs); /*crop_left*/
- cr = avc_get_ue(bs); /*crop_right*/
- ct = avc_get_ue(bs); /*crop_top*/
- cb = avc_get_ue(bs); /*crop_bottom*/
+ cl = bs_get_ue(bs); /*crop_left*/
+ cr = bs_get_ue(bs); /*crop_right*/
+ ct = bs_get_ue(bs); /*crop_top*/
+ cb = bs_get_ue(bs); /*crop_bottom*/
sps->width = 16*mb_width - 2*(cl + cr);
sps->height -= (2-sps->frame_mbs_only_flag)*2*(ct + cb);
@@ -1899,8 +1933,8 @@ s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps,
}
if (gf_bs_read_int(bs, 1)) { /* chroma_location_info_present_flag */
- avc_get_ue(bs); /* chroma_sample_location_type_top_field */
- avc_get_ue(bs); /* chroma_sample_location_type_bottom_field */
+ bs_get_ue(bs); /* chroma_sample_location_type_top_field */
+ bs_get_ue(bs); /* chroma_sample_location_type_bottom_field */
}
sps->vui.timing_info_present_flag = gf_bs_read_int(bs, 1);
@@ -1943,10 +1977,10 @@ s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps,
/*seq_ref_layer_chroma_phase_x_plus1_flag*/gf_bs_read_int(bs, 1);
/*seq_ref_layer_chroma_phase_y_plus1*/gf_bs_read_int(bs, 2);
}
- /*seq_scaled_ref_layer_left_offset*/ avc_get_se(bs);
- /*seq_scaled_ref_layer_top_offset*/avc_get_se(bs);
- /*seq_scaled_ref_layer_right_offset*/avc_get_se(bs);
- /*seq_scaled_ref_layer_bottom_offset*/avc_get_se(bs);
+ /*seq_scaled_ref_layer_left_offset*/ bs_get_se(bs);
+ /*seq_scaled_ref_layer_top_offset*/bs_get_se(bs);
+ /*seq_scaled_ref_layer_right_offset*/bs_get_se(bs);
+ /*seq_scaled_ref_layer_bottom_offset*/bs_get_se(bs);
}
if (/*seq_tcoeff_level_prediction_flag*/gf_bs_read_int(bs, 1)) {
/*adaptive_tcoeff_level_prediction_flag*/ gf_bs_read_int(bs, 1);
@@ -1956,7 +1990,7 @@ s32 AVC_ReadSeqInfo(char *sps_data, u32 sps_size, AVCState *avc, u32 subseq_sps,
/*svc_vui_parameters_present*/
if (gf_bs_read_int(bs, 1)) {
u32 i, vui_ext_num_entries_minus1;
- vui_ext_num_entries_minus1 = avc_get_ue(bs);
+ vui_ext_num_entries_minus1 = bs_get_ue(bs);
for (i=0; i <= vui_ext_num_entries_minus1; i++) {
u8 vui_ext_nal_hrd_parameters_present_flag, vui_ext_vcl_hrd_parameters_present_flag, vui_ext_timing_info_present_flag;
@@ -2001,7 +2035,7 @@ exit:
return sps_id;
}
-s32 AVC_ReadPictParamSet(char *pps_data, u32 pps_size, AVCState *avc)
+s32 gf_media_avc_read_pps(char *pps_data, u32 pps_size, AVCState *avc)
{
GF_BitStream *bs;
char *pps_data_without_emulation_bytes = NULL;
@@ -2017,7 +2051,10 @@ s32 AVC_ReadPictParamSet(char *pps_data, u32 pps_size, AVCState *avc)
pps_id = -1;
goto exit;
}
- pps_id = avc_get_ue(bs);
+ /*nal hdr*/gf_bs_read_u8(bs);
+
+
+ pps_id = bs_get_ue(bs);
if (pps_id>=255) {
pps_id = -1;
goto exit;
@@ -2025,7 +2062,7 @@ s32 AVC_ReadPictParamSet(char *pps_data, u32 pps_size, AVCState *avc)
pps = &avc->pps[pps_id];
if (!pps->status) pps->status = 1;
- pps->sps_id = avc_get_ue(bs);
+ pps->sps_id = bs_get_ue(bs);
if (pps->sps_id >= 32) {
pps->sps_id = 0;
pps_id = -1;
@@ -2039,19 +2076,19 @@ s32 AVC_ReadPictParamSet(char *pps_data, u32 pps_size, AVCState *avc)
avc->sps_active_idx = pps->sps_id; /*set active sps*/
/*pps->cabac = */gf_bs_read_int(bs, 1);
pps->pic_order_present= gf_bs_read_int(bs, 1);
- pps->slice_group_count= avc_get_ue(bs) + 1;
- if (pps->slice_group_count > 1 ) /*pps->mb_slice_group_map_type = */avc_get_ue(bs);
- /*pps->ref_count[0]= */avc_get_ue(bs) /*+ 1*/;
- /*pps->ref_count[1]= */avc_get_ue(bs) /*+ 1*/;
+ pps->slice_group_count= bs_get_ue(bs) + 1;
+ if (pps->slice_group_count > 1 ) /*pps->mb_slice_group_map_type = */bs_get_ue(bs);
+ /*pps->ref_count[0]= */bs_get_ue(bs) /*+ 1*/;
+ /*pps->ref_count[1]= */bs_get_ue(bs) /*+ 1*/;
/*
if ((pps->ref_count[0] > 32) || (pps->ref_count[1] > 32)) goto exit;
*/
/*pps->weighted_pred = */gf_bs_read_int(bs, 1);
/*pps->weighted_bipred_idc = */gf_bs_read_int(bs, 2);
- /*pps->init_qp = */avc_get_se(bs) /*+ 26*/;
- /*pps->init_qs= */avc_get_se(bs) /*+ 26*/;
- /*pps->chroma_qp_index_offset = */avc_get_se(bs);
+ /*pps->init_qp = */bs_get_se(bs) /*+ 26*/;
+ /*pps->init_qs= */bs_get_se(bs) /*+ 26*/;
+ /*pps->chroma_qp_index_offset = */bs_get_se(bs);
/*pps->deblocking_filter_parameters_present = */gf_bs_read_int(bs, 1);
/*pps->constrained_intra_pred = */gf_bs_read_int(bs, 1);
pps->redundant_pic_cnt_present = gf_bs_read_int(bs, 1);
@@ -2062,7 +2099,7 @@ exit:
return pps_id;
}
-s32 AVC_ReadSeqParamSetExtId(char *spse_data, u32 spse_size)
+s32 gf_media_avc_read_sps_ext(char *spse_data, u32 spse_size)
{
GF_BitStream *bs;
char *spse_data_without_emulation_bytes = NULL;
@@ -2074,9 +2111,9 @@ s32 AVC_ReadSeqParamSetExtId(char *spse_data, u32 spse_size)
spse_data_without_emulation_bytes_size = avc_remove_emulation_bytes(spse_data, spse_data_without_emulation_bytes, spse_size);
bs = gf_bs_new(spse_data_without_emulation_bytes, spse_data_without_emulation_bytes_size, GF_BITSTREAM_READ);
- sps_id = -1;
- if (bs)
- sps_id = avc_get_ue(bs);
+ /*nal header*/gf_bs_read_u8(bs);
+
+ sps_id = bs_get_ue(bs);
gf_bs_del(bs);
gf_free(spse_data_without_emulation_bytes);
@@ -2104,11 +2141,11 @@ static s32 avc_parse_slice(GF_BitStream *bs, AVCState *avc, Bool svc_idr_flag, A
s32 pps_id;
/*s->current_picture.reference= h->nal_ref_idc != 0;*/
- /*first_mb_in_slice = */avc_get_ue(bs);
- si->slice_type = avc_get_ue(bs);
+ /*first_mb_in_slice = */bs_get_ue(bs);
+ si->slice_type = bs_get_ue(bs);
if (si->slice_type > 9) return -1;
- pps_id = avc_get_ue(bs);
+ pps_id = bs_get_ue(bs);
if (pps_id>255) return -1;
si->pps = &avc->pps[pps_id];
if (!si->pps->slice_group_count) return -2;
@@ -2125,20 +2162,20 @@ static s32 avc_parse_slice(GF_BitStream *bs, AVCState *avc, Bool svc_idr_flag, A
si->bottom_field_flag = gf_bs_read_int(bs, 1);
}
if ((si->nal_unit_type==GF_AVC_NALU_IDR_SLICE) || svc_idr_flag)
- si->idr_pic_id = avc_get_ue(bs);
+ si->idr_pic_id = bs_get_ue(bs);
if (si->sps->poc_type==0) {
si->poc_lsb = gf_bs_read_int(bs, si->sps->log2_max_poc_lsb);
if (si->pps->pic_order_present && !si->field_pic_flag) {
- si->delta_poc_bottom = avc_get_se(bs);
+ si->delta_poc_bottom = bs_get_se(bs);
}
} else if ((si->sps->poc_type==1) && !si->sps->delta_pic_order_always_zero_flag) {
- si->delta_poc[0] = avc_get_se(bs);
+ si->delta_poc[0] = bs_get_se(bs);
if ((si->pps->pic_order_present==1) && !si->field_pic_flag)
- si->delta_poc[1] = avc_get_se(bs);
+ si->delta_poc[1] = bs_get_se(bs);
}
if (si->pps->redundant_pic_cnt_present) {
- si->redundant_pic_cnt = avc_get_ue(bs);
+ si->redundant_pic_cnt = bs_get_ue(bs);
}
return 0;
}
@@ -2149,11 +2186,11 @@ static s32 svc_parse_slice(GF_BitStream *bs, AVCState *avc, AVCSliceInfo *si)
s32 pps_id;
/*s->current_picture.reference= h->nal_ref_idc != 0;*/
- /*first_mb_in_slice = */avc_get_ue(bs);
- si->slice_type = avc_get_ue(bs);
+ /*first_mb_in_slice = */bs_get_ue(bs);
+ si->slice_type = bs_get_ue(bs);
if (si->slice_type > 9) return -1;
- pps_id = avc_get_ue(bs);
+ pps_id = bs_get_ue(bs);
if (pps_id>255)
return -1;
si->pps = &avc->pps[pps_id];
@@ -2174,20 +2211,20 @@ static s32 svc_parse_slice(GF_BitStream *bs, AVCState *avc, AVCSliceInfo *si)
if (si->field_pic_flag) si->bottom_field_flag = gf_bs_read_int(bs, 1);
}
if (si->nal_unit_type == GF_AVC_NALU_IDR_SLICE || si ->NalHeader.idr_pic_flag)
- si->idr_pic_id = avc_get_ue(bs);
+ si->idr_pic_id = bs_get_ue(bs);
if (si->sps->poc_type==0) {
si->poc_lsb = gf_bs_read_int(bs, si->sps->log2_max_poc_lsb);
if (si->pps->pic_order_present && !si->field_pic_flag) {
- si->delta_poc_bottom = avc_get_se(bs);
+ si->delta_poc_bottom = bs_get_se(bs);
}
} else if ((si->sps->poc_type==1) && !si->sps->delta_pic_order_always_zero_flag) {
- si->delta_poc[0] = avc_get_se(bs);
+ si->delta_poc[0] = bs_get_se(bs);
if ((si->pps->pic_order_present==1) && !si->field_pic_flag)
- si->delta_poc[1] = avc_get_se(bs);
+ si->delta_poc[1] = bs_get_se(bs);
}
if (si->pps->redundant_pic_cnt_present) {
- si->redundant_pic_cnt = avc_get_ue(bs);
+ si->redundant_pic_cnt = bs_get_ue(bs);
}
return 0;
}
@@ -2197,7 +2234,7 @@ static s32 avc_parse_recovery_point_sei(GF_BitStream *bs, AVCState *avc)
{
AVCSeiRecoveryPoint *rp = &avc->sei.recovery_point;
- rp->frame_cnt = avc_get_ue(bs);
+ rp->frame_cnt = bs_get_ue(bs);
rp->exact_match_flag = gf_bs_read_int(bs, 1);
rp->broken_link_flag = gf_bs_read_int(bs, 1);
rp->changing_slice_group_idc = gf_bs_read_int(bs, 2);
@@ -2379,7 +2416,7 @@ static void avc_compute_poc(AVCSliceInfo *si)
si->poc = field_poc[1];
}
-s32 AVC_ParseNALU(GF_BitStream *bs, u32 nal_hdr, AVCState *avc)
+s32 gf_media_avc_parse_nalu(GF_BitStream *bs, u32 nal_hdr, AVCState *avc)
{
u8 idr_flag;
s32 slice, ret;
@@ -2483,6 +2520,7 @@ s32 AVC_ParseNALU(GF_BitStream *bs, u32 nal_hdr, AVCState *avc)
break;
case GF_AVC_NALU_SEQ_PARAM:
case GF_AVC_NALU_PIC_PARAM:
+ case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
return 0;
default:
if (avc->s_info.nal_unit_type <= GF_AVC_NALU_IDR_SLICE) ret = 1;
@@ -2511,7 +2549,7 @@ s32 AVC_ParseNALU(GF_BitStream *bs, u32 nal_hdr, AVCState *avc)
return ret;
}
-u32 AVC_ReformatSEI_NALU(char *buffer, u32 nal_size, AVCState *avc)
+u32 gf_media_avc_reformat_sei(char *buffer, u32 nal_size, AVCState *avc)
{
u32 ptype, psize, hdr, written, var;
u64 start;
@@ -2671,7 +2709,7 @@ static u8 avc_get_sar_idx(u32 w, u32 h)
return 0xFF;
}
-GF_Err AVC_ChangePAR(GF_AVCConfig *avcc, s32 ar_n, s32 ar_d)
+GF_Err gf_media_avc_change_par(GF_AVCConfig *avcc, s32 ar_n, s32 ar_d)
{
GF_BitStream *orig, *mod;
AVCState avc;
@@ -2687,7 +2725,7 @@ GF_Err AVC_ChangePAR(GF_AVCConfig *avcc, s32 ar_n, s32 ar_d)
while ((slc = (GF_AVCConfigSlot *)gf_list_enum(avcc->sequenceParameterSets, &i))) {
char *no_emulation_buf = NULL;
u32 no_emulation_buf_size = 0, emulation_bytes = 0;
- idx = AVC_ReadSeqInfo(slc->data+1/*skip NALU type*/, slc->size-1, &avc, 0, &bit_offset);
+ idx = gf_media_avc_read_sps(slc->data, slc->size, &avc, 0, &bit_offset);
if (idx<0) {
if ( orig )
gf_bs_del(orig);
@@ -2704,14 +2742,15 @@ GF_Err AVC_ChangePAR(GF_AVCConfig *avcc, s32 ar_n, s32 ar_d)
mod = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
/*copy over till vui flag*/
- while (bit_offset) {
+ assert(bit_offset>=8);
+ while (bit_offset-8/*bit_offset doesn't take care of the first byte (NALU type)*/) {
flag = gf_bs_read_int(orig, 1);
gf_bs_write_int(mod, flag, 1);
bit_offset--;
}
/*check VUI*/
flag = gf_bs_read_int(orig, 1);
- gf_bs_write_int(mod, 1, 1);
+ gf_bs_write_int(mod, 1, 1); /*vui_parameters_present_flag*/
if (flag) {
/*aspect_ratio_info_present_flag*/
if (gf_bs_read_int(orig, 1)) {
@@ -2778,7 +2817,7 @@ GF_Err gf_avc_get_sps_info(char *sps_data, u32 sps_size, u32 *sps_id, u32 *width
memset(&avc, 0, sizeof(AVCState));
avc.sps_active_idx = -1;
- idx = AVC_ReadSeqInfo(sps_data+1/*skip NALU type*/, sps_size-1, &avc, 0, NULL);
+ idx = gf_media_avc_read_sps(sps_data, sps_size, &avc, 0, NULL);
if (idx<0) {
return GF_NON_COMPLIANT_BITSTREAM;
}
@@ -2792,11 +2831,634 @@ GF_Err gf_avc_get_sps_info(char *sps_data, u32 sps_size, u32 *sps_id, u32 *width
return GF_OK;
}
-#endif /*GPAC_DISABLE_AV_PARSERS*/
+GF_EXPORT
+GF_Err gf_avc_get_pps_info(char *pps_data, u32 pps_size, u32 *pps_id, u32 *sps_id)
+{
+ GF_BitStream *bs;
+ char *pps_data_without_emulation_bytes = NULL;
+ u32 pps_data_without_emulation_bytes_size = 0;
+ GF_Err e = GF_OK;
+
+ /*PPS still contains emulation bytes*/
+ pps_data_without_emulation_bytes = gf_malloc(pps_size*sizeof(char));
+ pps_data_without_emulation_bytes_size = avc_remove_emulation_bytes(pps_data, pps_data_without_emulation_bytes, pps_size);
+ bs = gf_bs_new(pps_data_without_emulation_bytes, pps_data_without_emulation_bytes_size, GF_BITSTREAM_READ);
+ if (!bs) {
+ e = GF_NON_COMPLIANT_BITSTREAM;
+ goto exit;
+ }
+ *pps_id = bs_get_ue(bs);
+ *sps_id = bs_get_ue(bs);
+exit:
+ gf_bs_del(bs);
+ gf_free(pps_data_without_emulation_bytes);
+ return e;
+}
-#ifndef GPAC_DISABLE_AV_PARSERS
+/**********
+HEVC parsing
+**********/
+
+Bool gf_media_hevc_slice_is_intra(HEVCState *hevc)
+{
+ switch (hevc->s_info.nal_unit_type) {
+ case GF_HEVC_NALU_SLICE_BLA_W_LP:
+ case GF_HEVC_NALU_SLICE_BLA_W_DLP:
+ case GF_HEVC_NALU_SLICE_BLA_N_LP:
+ case GF_HEVC_NALU_SLICE_IDR_W_DLP:
+ case GF_HEVC_NALU_SLICE_IDR_N_LP:
+ case GF_HEVC_NALU_SLICE_CRA:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+Bool gf_media_hevc_slice_is_IDR(HEVCState *hevc)
+{
+ if (hevc->sei.recovery_point.valid)
+ {
+ hevc->sei.recovery_point.valid = 0;
+ return 1;
+ }
+ switch (hevc->s_info.nal_unit_type) {
+ case GF_HEVC_NALU_SLICE_IDR_W_DLP:
+ case GF_HEVC_NALU_SLICE_IDR_N_LP:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static s32 hevc_parse_slice_segment(GF_BitStream *bs, HEVCState *hevc, HEVCSliceInfo *si)
+{
+ HEVC_PPS *pps;
+ HEVC_SPS *sps;
+ s32 pps_id;
+ Bool dependent_slice_segment_flag = 0;
+ Bool first_slice_segment_in_pic_flag = gf_bs_read_int(bs, 1);
+ Bool RapPicFlag = 0;
+ Bool IDRPicFlag = 0;
+
+ switch (si->nal_unit_type) {
+ case GF_HEVC_NALU_SLICE_IDR_W_DLP:
+ case GF_HEVC_NALU_SLICE_IDR_N_LP:
+ IDRPicFlag = 1;
+ RapPicFlag = 1;
+ break;
+ case GF_HEVC_NALU_SLICE_BLA_W_LP:
+ case GF_HEVC_NALU_SLICE_BLA_W_DLP:
+ case GF_HEVC_NALU_SLICE_BLA_N_LP:
+ case GF_HEVC_NALU_SLICE_CRA:
+ RapPicFlag = 1;
+ break;
+ }
+
+ if (RapPicFlag) {
+ /*Bool no_output_of_prior_pics_flag = */gf_bs_read_int(bs, 1);
+ }
+ pps_id = bs_get_ue(bs);
+ if (pps_id>=64) return -1;
+
+ pps = &hevc->pps[pps_id];
+ sps = &hevc->sps[pps->sps_id];
+ si->sps = sps;
+ si->pps = pps;
+
+ if (!first_slice_segment_in_pic_flag && pps->dependent_slice_segments_enabled_flag) {
+ dependent_slice_segment_flag = gf_bs_read_int(bs, 1);
+ }
+
+ {
+ if (!first_slice_segment_in_pic_flag) {
+ /*slice_segment_address = */gf_bs_read_int(bs, sps->bitsSliceSegmentAddress);
+ }
+ }
+
+ if( !dependent_slice_segment_flag ) {
+ gf_bs_read_int(bs, pps->num_extra_slice_header_bits);
+
+ si->slice_type = bs_get_ue(bs);
+
+ if(pps->output_flag_present_flag)
+ /*pic_output_flag = */gf_bs_read_int(bs, 1);
+
+ if (sps->separate_colour_plane_flag == 1)
+ /*colour_plane_id = */gf_bs_read_int(bs, 2);
+
+ if (IDRPicFlag) {
+ si->poc_lsb = 0;
+ } else {
+ si->poc_lsb = gf_bs_read_int(bs, sps->log2_max_pic_order_cnt_lsb);
+ }
+ }
+ return 0;
+}
+
+static void hevc_compute_poc(HEVCSliceInfo *si)
+{
+ u32 max_poc_lsb = 1 << (si->sps->log2_max_pic_order_cnt_lsb);
+
+ /* frame_num_offset */
+ switch (si->nal_unit_type) {
+ case GF_HEVC_NALU_SLICE_IDR_W_DLP:
+ case GF_HEVC_NALU_SLICE_IDR_N_LP:
+ case GF_HEVC_NALU_SLICE_CRA:
+ si->poc_lsb_prev = 0;
+ si->poc_msb_prev = 0;
+ break;
+ }
+
+ if ((si->poc_lsb < si->poc_lsb_prev) && (si->poc_lsb_prev - si->poc_lsb >= max_poc_lsb / 2) )
+ si->poc_msb = si->poc_msb_prev + max_poc_lsb;
+ else if ((si->poc_lsb > si->poc_lsb_prev) && (si->poc_lsb - si->poc_lsb_prev > max_poc_lsb / 2))
+ si->poc_msb = si->poc_msb_prev - max_poc_lsb;
+ else
+ si->poc_msb = si->poc_msb_prev;
+
+ switch (si->nal_unit_type) {
+ case GF_HEVC_NALU_SLICE_BLA_W_LP:
+ case GF_HEVC_NALU_SLICE_BLA_W_DLP:
+ case GF_HEVC_NALU_SLICE_BLA_N_LP:
+ si->poc_msb = 0;
+ break;
+ }
+ si->poc = si->poc_msb + si->poc_lsb;
+}
+
+void profile_tier_level(GF_BitStream *bs, Bool ProfilePresentFlag, u8 MaxNumSubLayersMinus1, HEVC_ProfileTierLevel *ptl)
+{
+ u32 i;
+ if (ProfilePresentFlag) {
+ ptl->profile_space = gf_bs_read_int(bs, 2);
+ ptl->tier_flag = gf_bs_read_int(bs, 1);
+ ptl->profile_idc = gf_bs_read_int(bs, 5);
+
+ ptl->profile_compatibility_flag = gf_bs_read_int(bs, 32);
+
+ /*general_reserved_zero_16bits = */gf_bs_read_int(bs, 16);
+ }
+ ptl->level_idc = gf_bs_read_int(bs, 8);
+ for (i=0; isub_ptl[i].profile_present_flag = gf_bs_read_int(bs, 1);
+ ptl->sub_ptl[i].level_present_flag = gf_bs_read_int(bs, 1);
+ if (ProfilePresentFlag && ptl->sub_ptl[i].profile_present_flag) {
+ ptl->sub_ptl[i].profile_space = gf_bs_read_int(bs, 2);
+ ptl->sub_ptl[i].tier_flag = gf_bs_read_int(bs, 1);
+ ptl->sub_ptl[i].profile_idc = gf_bs_read_int(bs, 5);
+ ptl->sub_ptl[i].profile_compatibility_flag = gf_bs_read_int(bs, 32);
+ /*sub_layer_reserved_zero_16bits*/gf_bs_read_int(bs, 16);
+ }
+ if (ptl->sub_ptl[i].level_present_flag)
+ ptl->sub_ptl[i].level_idc = gf_bs_read_int(bs, 8);
+ }
+}
+
+void bit_rate_pic_rate_info(GF_BitStream *bs, u8 level_low, u8 level_high, HEVC_VPS *vps)
+{
+ u8 i;
+ for (i=level_low; i<=level_high; i++) {
+ Bool bit_rate_info_present_flag = gf_bs_read_int(bs, 1);
+ Bool pic_rate_info_present_flag = gf_bs_read_int(bs, 1);
+ if (bit_rate_info_present_flag) {
+ vps->rates[i].avg_bit_rate = gf_bs_read_int(bs, 16);
+ vps->rates[i].max_bit_rate = gf_bs_read_int(bs, 16);
+ }
+ if (pic_rate_info_present_flag) {
+ vps->rates[i].constand_pic_rate_idc = gf_bs_read_int(bs, 2);
+ vps->rates[i].avg_pic_rate = gf_bs_read_int(bs, 16);
+ }
+ }
+}
+
+s32 gf_media_hevc_read_vps(char *data, u32 size, HEVCState *hevc)
+{
+ GF_BitStream *bs;
+ char *data_without_emulation_bytes = NULL;
+ u32 data_without_emulation_bytes_size = 0;
+ s32 vps_id = -1;
+ HEVC_VPS *vps;
+
+ /*still contains emulation bytes*/
+ data_without_emulation_bytes = gf_malloc(size*sizeof(char));
+ data_without_emulation_bytes_size = avc_remove_emulation_bytes(data, data_without_emulation_bytes, size);
+ bs = gf_bs_new(data_without_emulation_bytes, data_without_emulation_bytes_size, GF_BITSTREAM_READ);
+ if (!bs) goto exit;
+
+ gf_bs_read_u16(bs);
+
+ vps_id = gf_bs_read_int(bs, 4);
+
+ if (vps_id>=16) goto exit;
+
+ vps = &hevc->vps[vps_id];
+ if (!vps->state) {
+ vps->id = vps_id;
+ vps->state = 1;
+ }
+
+ /*vps_temporal_id_nesting_flag = */ gf_bs_read_int(bs, 1);
+ gf_bs_read_int(bs, 2);
+ gf_bs_read_int(bs, 6);
+ vps->max_sub_layer = gf_bs_read_int(bs, 3) + 1;
+ gf_bs_read_int(bs, 16);
+ profile_tier_level(bs, 1, vps->max_sub_layer-1, &vps->ptl);
+ bit_rate_pic_rate_info(bs, 0, vps->max_sub_layer-1, vps);
+
+
+ //and we don't care about the rest for now
+exit:
+ gf_bs_del(bs);
+ gf_free(data_without_emulation_bytes);
+ return vps_id;
+}
+
+
+static Bool parse_short_term_ref_pic_set(GF_BitStream *bs, HEVC_SPS *sps, u32 idx_rps)
+{
+ u32 i;
+ Bool inter_ref_pic_set_prediction_flag = 0;
+ if (idx_rps != 0)
+ inter_ref_pic_set_prediction_flag = gf_bs_read_int(bs, 1);
+
+ if (inter_ref_pic_set_prediction_flag ) {
+ HEVC_ReferencePictureSets *ref_ps, *rps;
+ u32 delta_idx_minus1 = 0;
+ u32 ref_idx;
+ u32 delta_rps_sign;
+ u32 abs_delta_rps_minus1, nb_ref_pics;
+ s32 deltaRPS;
+ u32 k = 0, k0 = 0, k1 = 0;
+ if (idx_rps == sps->num_short_term_ref_pic_sets)
+ delta_idx_minus1 = bs_get_ue(bs);
+
+ assert(delta_idx_minus1 <= idx_rps - 1);
+ ref_idx = idx_rps - 1 - delta_idx_minus1;
+ delta_rps_sign = gf_bs_read_int(bs, 1);
+ abs_delta_rps_minus1 = bs_get_ue(bs);
+ deltaRPS = (1 - (delta_rps_sign<<1)) * (abs_delta_rps_minus1 + 1);
+
+ rps = &sps->rps[idx_rps];
+ ref_ps = &sps->rps[ref_idx];
+ nb_ref_pics = ref_ps->num_negative_pics + ref_ps->num_positive_pics;
+ for (i=0; i<=nb_ref_pics; i++) {
+ s32 ref_idc;
+ s32 used_by_curr_pic_flag = gf_bs_read_int(bs, 1);
+ ref_idc = used_by_curr_pic_flag ? 1 : 0;
+ if ( !used_by_curr_pic_flag ) {
+ used_by_curr_pic_flag = gf_bs_read_int(bs, 1);
+ ref_idc = used_by_curr_pic_flag << 1;
+ }
+ if ((ref_idc==1) || (ref_idc== 2)) {
+ s32 deltaPOC = deltaRPS;
+ if (i < nb_ref_pics)
+ deltaPOC += ref_ps->delta_poc[i];
+
+ rps->delta_poc[k] = deltaPOC;
+
+ if (deltaPOC < 0) k0++;
+ else k1++;
+
+ k++;
+ }
+ }
+ rps->num_negative_pics = k0;
+ rps->num_positive_pics = k1;
+ } else {
+ s32 prev = 0, poc = 0;
+ sps->rps[idx_rps].num_negative_pics = bs_get_ue(bs);
+ sps->rps[idx_rps].num_positive_pics = bs_get_ue(bs);
+ for (i=0; irps[idx_rps].num_negative_pics; i++) {
+ u32 delta_poc_s0_minus1 = bs_get_ue(bs);
+ poc = prev - delta_poc_s0_minus1 - 1;
+ prev = poc;
+ sps->rps[idx_rps].delta_poc[i] = poc;
+ /*used_by_curr_pic_s1_flag[ i ] = */gf_bs_read_int(bs, 1);
+ }
+ for (i=0; irps[idx_rps].num_positive_pics; i++) {
+ u32 delta_poc_s1_minus1 = bs_get_ue(bs);
+ poc = prev + delta_poc_s1_minus1 + 1;
+ prev = poc;
+ sps->rps[idx_rps].delta_poc[i] = poc;
+ /*used_by_curr_pic_s1_flag[ i ] = */gf_bs_read_int(bs, 1);
+ }
+ }
+ return 1;
+}
+
+s32 gf_media_hevc_read_sps(char *data, u32 size, HEVCState *hevc)
+{
+ GF_BitStream *bs;
+ char *data_without_emulation_bytes = NULL;
+ u32 data_without_emulation_bytes_size = 0;
+ s32 vps_id, sps_id = -1;
+ u8 max_sub_layers_minus1;
+ u32 i, nb_CTUs, depth;
+ u32 log2_diff_max_min_luma_coding_block_size;
+ u32 log2_min_transform_block_size, log2_min_luma_coding_block_size;
+
+ Bool sps_sub_layer_ordering_info_present_flag;
+ HEVC_SPS *sps;
+ HEVC_ProfileTierLevel ptl;
+
+ /*still contains emulation bytes*/
+ data_without_emulation_bytes = gf_malloc(size*sizeof(char));
+ data_without_emulation_bytes_size = avc_remove_emulation_bytes(data, data_without_emulation_bytes, size);
+ bs = gf_bs_new(data_without_emulation_bytes, data_without_emulation_bytes_size, GF_BITSTREAM_READ);
+ if (!bs) goto exit;
+
+ gf_bs_read_u16(bs);
+
+ vps_id = gf_bs_read_int(bs, 4);
+ if (vps_id>=16) goto exit;
+
+ max_sub_layers_minus1 = gf_bs_read_int(bs, 3);
+ /*temporal_id_nesting_flag = */gf_bs_read_int(bs, 1);
+ memset(&ptl, 0, sizeof(ptl));
+ profile_tier_level(bs, 1, max_sub_layers_minus1, &ptl);
+
+ sps_id = bs_get_ue(bs);
+ if (sps_id>=16) goto exit;
+ sps = &hevc->sps[sps_id];
+ if (!sps->state) {
+ sps->state = 1;
+ sps->id = sps_id;
+ sps->vps_id = vps_id;
+ }
+ sps->ptl = ptl;
+
+ sps->chroma_format_idc = bs_get_ue(bs);
+ if (sps->chroma_format_idc==3)
+ sps->separate_colour_plane_flag = gf_bs_read_int(bs, 1);
+ sps->width = bs_get_ue(bs);
+ sps->height = bs_get_ue(bs);
+ if (gf_bs_read_int(bs, 1)) {
+ sps->cw_left = bs_get_ue(bs);
+ sps->cw_right = bs_get_ue(bs);
+ sps->cw_top = bs_get_ue(bs);
+ sps->cw_bottom = bs_get_ue(bs);
+ }
+ sps->bit_depth_luma = 8 + bs_get_ue(bs);
+ sps->bit_depth_chroma = 8 + bs_get_ue(bs);
+
+ sps->log2_max_pic_order_cnt_lsb = 4 + bs_get_ue(bs);
+
+ sps_sub_layer_ordering_info_present_flag = gf_bs_read_int(bs, 1);
+ for(i= sps_sub_layer_ordering_info_present_flag ? 0 : max_sub_layers_minus1; i<=max_sub_layers_minus1; i++) {
+ /*max_dec_pic_buffering = */ bs_get_ue(bs);
+ /*num_reorder_pics = */ bs_get_ue(bs);
+ /*max_latency_increase = */ bs_get_ue(bs);
+ }
+
+ log2_min_luma_coding_block_size = 3 + bs_get_ue(bs);
+ log2_diff_max_min_luma_coding_block_size = bs_get_ue(bs);
+ sps->max_CU_width = ( 1<<(log2_min_luma_coding_block_size + log2_diff_max_min_luma_coding_block_size) );
+ sps->max_CU_height = ( 1<<(log2_min_luma_coding_block_size + log2_diff_max_min_luma_coding_block_size) );
+
+ log2_min_transform_block_size = 2 + bs_get_ue(bs);
+ /*log2_max_transform_block_size = log2_min_transform_block_size + */bs_get_ue(bs);
+
+ depth = 0;
+ /*u32 max_transform_hierarchy_depth_inter = */bs_get_ue(bs);
+ /*u32 max_transform_hierarchy_depth_intra = */bs_get_ue(bs);
+ while( (u32) ( sps->max_CU_width >> log2_diff_max_min_luma_coding_block_size ) > (u32) ( 1 << ( log2_min_transform_block_size + depth ) ) )
+ {
+ depth++;
+ }
+ sps->max_CU_depth = log2_diff_max_min_luma_coding_block_size + depth;
+
+ nb_CTUs = ((sps->width + sps->max_CU_width -1) / sps->max_CU_width) * ((sps->height + sps->max_CU_height-1) / sps->max_CU_height);
+ sps->bitsSliceSegmentAddress = 0;
+ while (nb_CTUs > (u32) (1 << sps->bitsSliceSegmentAddress)) {
+ sps->bitsSliceSegmentAddress++;
+ }
+
+ if (/*scaling_list_enable_flag = */ gf_bs_read_int(bs, 1)) {
+ if (/*sps_scaling_list_data_present_flag=*/gf_bs_read_int(bs, 1) ) {
+ //scaling_list_data( )
+ }
+ }
+ /*asymmetric_motion_partitions_enabled_flag= */ gf_bs_read_int(bs, 1);
+ /*sample_adaptive_offset_enabled_flag= */ gf_bs_read_int(bs, 1);
+ if (/*pcm_enabled_flag= */ gf_bs_read_int(bs, 1) ) {
+ /*pcm_sample_bit_depth_luma_minus1=*/gf_bs_read_int(bs, 4);
+ /*pcm_sample_bit_depth_chroma_minus1=*/gf_bs_read_int(bs, 4);
+ /*log2_min_pcm_luma_coding_block_size_minus3= */ bs_get_ue(bs);
+ /*log2_diff_max_min_pcm_luma_coding_block_size = */ bs_get_ue(bs);
+ /*pcm_loop_filter_disable_flag=*/gf_bs_read_int(bs, 1);
+ }
+ sps->num_short_term_ref_pic_sets = bs_get_ue(bs);
+ for (i=0;inum_short_term_ref_pic_sets; i++) {
+ Bool ret = parse_short_term_ref_pic_set(bs, sps, i);
+ /*cannot parse short_term_ref_pic_set, skip VUI parsing*/
+ if (!ret) goto exit;
+ }
+ if (/*long_term_ref_pics_present_flag */ gf_bs_read_int(bs, 1) ) {
+ sps->num_long_term_ref_pic_sps = bs_get_ue(bs);
+ for (i=0; inum_long_term_ref_pic_sps; i++) {
+ /*lt_ref_pic_poc_lsb_sps=*/gf_bs_read_int(bs, sps->log2_max_pic_order_cnt_lsb);
+ /*used_by_curr_pic_lt_sps_flag*/gf_bs_read_int(bs, 1);
+ }
+ }
+ /*sps_temporal_mvp_enable_flag*/gf_bs_read_int(bs, 1);
+ /*strong_intra_smoothing_enable_flag*/gf_bs_read_int(bs, 1);
+ if (/*vui_parameters_present_flag*/gf_bs_read_int(bs, 1)) {
+ //vui param
+ }
+ if (/*sps_extension_flag*/gf_bs_read_int(bs, 1)) {
+ while (gf_bs_available(bs)) {
+ }
+ }
+
+exit:
+ gf_bs_del(bs);
+ gf_free(data_without_emulation_bytes);
+ return sps_id;
+}
+
+s32 gf_media_hevc_read_pps(char *data, u32 size, HEVCState *hevc)
+{
+ u32 i;
+ GF_BitStream *bs;
+ char *data_without_emulation_bytes = NULL;
+ u32 data_without_emulation_bytes_size = 0;
+ s32 pps_id = -1;
+ HEVC_PPS *pps;
+
+ /*still contains emulation bytes*/
+ data_without_emulation_bytes = gf_malloc(size*sizeof(char));
+ data_without_emulation_bytes_size = avc_remove_emulation_bytes(data, data_without_emulation_bytes, size);
+ bs = gf_bs_new(data_without_emulation_bytes, data_without_emulation_bytes_size, GF_BITSTREAM_READ);
+ if (!bs) goto exit;
+
+ gf_bs_read_u16(bs);
+
+ pps_id = bs_get_ue(bs);
+
+ if (pps_id>=64) goto exit;
+ pps = &hevc->pps[pps_id];
+
+ if (!pps->state) {
+ pps->id = pps_id;
+ pps->state = 1;
+ }
+ pps->sps_id = bs_get_ue(bs);
+ hevc->sps_active_idx = pps->sps_id; /*set active sps*/
+ pps->dependent_slice_segments_enabled_flag = gf_bs_read_int(bs, 1);
+
+ /*sign_data_hiding_flag = */gf_bs_read_int(bs, 1);
+ /*cabac_init_present_flag = */gf_bs_read_int(bs, 1);
+ /*num_ref_idx_l0_default_active_minus1 = */bs_get_ue(bs);
+ /*num_ref_idx_l1_default_active_minus1 = */bs_get_ue(bs);
+ /*pic_init_qp_minus26 = */bs_get_se(bs);
+ /*constrained_intra_pred_flag = */gf_bs_read_int(bs, 1);
+ /*transform_skip_enabled_flag = */gf_bs_read_int(bs, 1);
+ if (/*cu_qp_delta_enabled_flag = */gf_bs_read_int(bs, 1) )
+ /*diff_cu_qp_delta_depth = */bs_get_ue(bs);
+
+ /*pic_cb_qp_offset = */bs_get_se(bs);
+ /*pic_cr_qp_offset = */bs_get_se(bs);
+ /*pic_slice_chroma_qp_offsets_present_flag = */gf_bs_read_int(bs, 1);
+ /*weighted_pred_flag = */gf_bs_read_int(bs, 1);
+ /*weighted_bipred_flag = */gf_bs_read_int(bs, 1);
+ pps->output_flag_present_flag = gf_bs_read_int(bs, 1);
+ /*transquant_bypass_enable_flag = */gf_bs_read_int(bs, 1);
+ pps->tiles_enabled_flag = gf_bs_read_int(bs, 1);
+ /*entropy_coding_sync_enabled_flag = */gf_bs_read_int(bs, 1);
+ if (pps->tiles_enabled_flag) {
+ u32 num_tile_columns_minus1 = bs_get_ue(bs);
+ u32 num_tile_rows_minus1 = bs_get_ue(bs);
+ pps->uniform_spacing_flag = gf_bs_read_int(bs, 1);
+ if (!pps->uniform_spacing_flag ) {
+ for( i = 0; i < num_tile_columns_minus1; i++ ) {
+ /*column_width_minus1[ i ] = */bs_get_ue(bs);
+ }
+ for( i = 0; i < num_tile_rows_minus1; i++ ) {
+ /*row_height_minus1[ i ] = */bs_get_ue(bs);
+ }
+ }
+ /*loop_filter_across_tiles_enabled_flag = */gf_bs_read_int(bs, 1);
+ }
+ /*loop_filter_across_slices_enabled_flag = */gf_bs_read_int(bs, 1);
+ if( /*deblocking_filter_control_present_flag = */gf_bs_read_int(bs, 1) ) {
+ /*deblocking_filter_override_enabled_flag= */gf_bs_read_int(bs, 1);
+ if (/*pic_disable_deblocking_filter_flag= */gf_bs_read_int(bs, 1) ) {
+ /*beta_offset_div2 = */bs_get_se(bs);
+ /*tc_offset_div2 = */bs_get_se(bs);
+ }
+ }
+ if (/*pic_scaling_list_data_present_flag = */gf_bs_read_int(bs, 1) ) {
+ //scaling_list_data( )
+ assert(0 && "not implemented");
+ }
+ /*lists_modification_present_flag = */gf_bs_read_int(bs, 1);
+ /*log2_parallel_merge_level_minus2 = */bs_get_ue(bs);
+ pps->num_extra_slice_header_bits = gf_bs_read_int(bs, 3);
+ pps->slice_segment_header_extension_present_flag = gf_bs_read_int(bs, 1);
+ if ( /*pps_extension_flag= */gf_bs_read_int(bs, 1) ) {
+ while (gf_bs_available(bs) ) {
+ //pps_extension_data_flag u(1)
+ }
+ }
+
+exit:
+ gf_bs_del(bs);
+ gf_free(data_without_emulation_bytes);
+ return pps_id;
+}
+
+
+s32 gf_media_hevc_parse_nalu(GF_BitStream *bs, HEVCState *hevc, u8 *nal_unit_type, u8 *temporal_id)
+{
+ u32 reserved;
+ s32 slice, ret;
+ HEVCSliceInfo n_state;
+
+ slice = 0;
+ memcpy(&n_state, &hevc->s_info, sizeof(HEVCSliceInfo));
+
+ reserved = gf_bs_read_int(bs, 1);
+ if (reserved) return -1;
+
+ *nal_unit_type = n_state.nal_unit_type = gf_bs_read_int(bs, 6);
+ reserved = gf_bs_read_int(bs, 6);
+// if (reserved) return -1;
+
+ *temporal_id = n_state.temporal_id = gf_bs_read_int(bs, 3);
+
+ ret = 0;
+ switch (n_state.nal_unit_type) {
+ case GF_HEVC_NALU_ACCESS_UNIT:
+ case GF_HEVC_NALU_END_OF_SEQ:
+ case GF_HEVC_NALU_END_OF_STREAM:
+ ret = 1;
+ break;
+
+
+ /*slice_layer_rbsp*/
+// case GF_HEVC_NALU_SLICE_STSA_N:
+// case GF_HEVC_NALU_SLICE_STSA_R:
+ case GF_HEVC_NALU_SLICE_RADL_N:
+// case GF_HEVC_NALU_SLICE_RADL_R:
+ case GF_HEVC_NALU_SLICE_RASL_N:
+// case GF_HEVC_NALU_SLICE_RASL_R:
+ break;
+
+ /*slice_segment_layer_rbsp*/
+ case GF_HEVC_NALU_SLICE_TRAIL_N:
+ case GF_HEVC_NALU_SLICE_TRAIL_R:
+ case GF_HEVC_NALU_SLICE_TSA_N:
+ case GF_HEVC_NALU_SLICE_TSA_R:
+ case GF_HEVC_NALU_SLICE_STSA_N:
+ case GF_HEVC_NALU_SLICE_STSA_R:
+
+ case GF_HEVC_NALU_SLICE_BLA_W_LP:
+ case GF_HEVC_NALU_SLICE_BLA_W_DLP:
+ case GF_HEVC_NALU_SLICE_BLA_N_LP:
+ case GF_HEVC_NALU_SLICE_IDR_W_DLP:
+ case GF_HEVC_NALU_SLICE_IDR_N_LP:
+ case GF_HEVC_NALU_SLICE_CRA:
+ case GF_HEVC_NALU_SLICE_RADL_R:
+ case GF_HEVC_NALU_SLICE_RASL_R:
+ slice = 1;
+ /* slice - read the info and compare.*/
+ ret = hevc_parse_slice_segment(bs, hevc, &n_state);
+ if (ret<0) return ret;
+
+ hevc_compute_poc(&n_state);
+
+ ret = 0;
+
+ if (hevc->s_info.poc != n_state.poc) {
+ ret=1;
+ break;
+ }
+ break;
+ case GF_HEVC_NALU_SEQ_PARAM:
+ case GF_HEVC_NALU_PIC_PARAM:
+ case GF_HEVC_NALU_VID_PARAM:
+ return 0;
+ default:
+ break;
+ }
+
+ /* save _prev values */
+ if (ret && hevc->s_info.sps) {
+ n_state.frame_num_offset_prev = hevc->s_info.frame_num_offset;
+ n_state.frame_num_prev = hevc->s_info.frame_num;
+
+ n_state.poc_lsb_prev = hevc->s_info.poc_lsb;
+ n_state.poc_msb_prev = hevc->s_info.poc_msb;
+
+ }
+ if (slice) hevc_compute_poc(&n_state);
+ memcpy(&hevc->s_info, &n_state, sizeof(HEVCSliceInfo));
+ return ret;
+}
+
static u32 AC3_FindSyncCode(u8 *buf, u32 buflen)
{
diff --git a/src/media_tools/dash_client.c b/src/media_tools/dash_client.c
index 3336f9e..9b30691 100644
--- a/src/media_tools/dash_client.c
+++ b/src/media_tools/dash_client.c
@@ -28,8 +28,13 @@
#include
#include
#include
+#include
#include
+#ifndef _WIN32_WCE
+#include
+#endif
+
#ifndef GPAC_DISABLE_DASH_CLIENT
/*set to 1 if you want MPD to use SegmentTemplate if possible instead of SegmentList*/
@@ -60,6 +65,7 @@ struct __dash_client
u32 max_cache_duration;
u32 auto_switch_count;
Bool keep_files, disable_switching, allow_local_mpd_update;
+ Bool is_m3u8;
GF_DASHInitialSelectionMode first_select_mode;
@@ -135,6 +141,8 @@ struct __dash_group
u32 prev_active_rep_index;
+ Bool timeline_setup;
+
GF_DASHGroupSelection selection;
@@ -148,6 +156,7 @@ struct __dash_group
u32 nb_segments_in_rep;
Double segment_duration;
+ Bool was_segment_base;
/*local file playback, do not delete them*/
Bool local_files;
/*next segment to download for this group*/
@@ -207,6 +216,64 @@ Bool gf_dash_check_mpd_root_type(const char *local_url)
return 0;
}
+static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group)
+{
+ u32 sec, frac;
+#ifndef _WIN32_WCE
+ time_t gtime;
+ struct tm *_t;
+#endif
+ u64 current_time;
+
+ if (mpd->type==GF_MPD_TYPE_STATIC)
+ return;
+
+ /*M3U8 does not use NTP sync */
+ if (group->dash->is_m3u8)
+ return;
+
+ gf_net_get_ntp(&sec, &frac);
+
+#ifndef _WIN32_WCE
+ gtime = sec - GF_NTP_SEC_1900_TO_1970;
+ _t = gmtime(>ime);
+ current_time = mktime(_t);
+#else
+ current_time = sec - GF_NTP_SEC_1900_TO_1970;
+#endif
+ if (current_time < mpd->availabilityStartTime) current_time = 0;
+ else current_time -= mpd->availabilityStartTime;
+
+ if (current_time < group->period->start) current_time = 0;
+ else current_time -= group->period->start;
+
+#if 0
+ {
+ s32 diff = (s32) current_time - (s32) (mpd->media_presentation_duration/1000);
+ if (ABS(diff)>10) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Broken UTC timing in client or server - got Media URL is not set in segment list\n"));
+
+ }
+ current_time = mpd->media_presentation_duration/1000;
+ }
+#endif
+
+ frac = mpd->time_shift_buffer_depth/1000;
+ if (current_time < frac) current_time = 0;
+ else current_time -= frac;
+
+
+ if (group->segment_duration) {
+ Double nb_seg = (Double) current_time;
+ nb_seg /= group->segment_duration;
+ frac = (u32) nb_seg;
+ group->download_segment_index = frac;
+ group->nb_segments_in_rep = frac + 10;
+ } else {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Segment duration unknown - cannot estimate current startNumber\n"));
+ }
+}
+
void gf_dash_group_check_switch(GF_DASHFileIO *dash_io, GF_DASH_Group *group, Bool download_active)
{
u32 download_rate;
@@ -279,7 +346,7 @@ static Bool gf_dash_is_m3u8_mime(const char * mime) {
* Parameters are identical to the ones of gf_term_download_new.
* \see gf_term_download_new()
*/
-GF_Err gf_dash_download_resource(GF_DASHFileIO *dash_io, GF_DASHFileIOSession *sess, const char *url, u64 start_range, u64 end_range, Bool persistent, GF_DASH_Group *group)
+GF_Err gf_dash_download_resource(GF_DASHFileIO *dash_io, GF_DASHFileIOSession *sess, const char *url, u64 start_range, u64 end_range, u32 persistent_mode, GF_DASH_Group *group)
{
Bool had_sess = 0;
Bool retry = 1;
@@ -288,7 +355,7 @@ GF_Err gf_dash_download_resource(GF_DASHFileIO *dash_io, GF_DASHFileIOSession *s
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Downloading %s...\n", url));
if (! *sess) {
- *sess = dash_io->create(dash_io, persistent, url);
+ *sess = dash_io->create(dash_io, persistent_mode ? 1 : 0, url);
if (!(*sess)){
assert(0);
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot try to download %s... OUT of memory ?\n", url));
@@ -296,22 +363,24 @@ GF_Err gf_dash_download_resource(GF_DASHFileIO *dash_io, GF_DASHFileIOSession *s
}
} else {
had_sess = 1;
- e = dash_io->setup_from_url(dash_io, *sess, url);
- if (e) {
- GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot resetup session for url %s: %s\n", url, gf_error_to_string(e) ));
- return e;
+ if (persistent_mode!=2) {
+ e = dash_io->setup_from_url(dash_io, *sess, url);
+ if (e) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot resetup session for url %s: %s\n", url, gf_error_to_string(e) ));
+ return e;
+ }
}
}
retry:
if (end_range) {
- e = dash_io->set_range(dash_io, *sess, start_range, end_range);
+ e = dash_io->set_range(dash_io, *sess, start_range, end_range, (persistent_mode==2) ? 0 : 1);
if (e) {
if (had_sess) {
dash_io->del(dash_io, *sess);
*sess = NULL;
- return gf_dash_download_resource(dash_io, sess, url, start_range, end_range, persistent, group);
+ return gf_dash_download_resource(dash_io, sess, url, start_range, end_range, persistent_mode ? 1 : 0, group);
}
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot setup byte-range download for %s: %s\n", url, gf_error_to_string(e) ));
return e;
@@ -411,13 +480,6 @@ static void gf_dash_get_segment_duration(GF_MPD_Representation *rep, GF_MPD_Adap
*nb_segments = timescale = 0;
duration = 0;
- /*single segment*/
- if (rep->segment_base || set->segment_base || period->segment_base) {
- *max_seg_duration = mpd->media_presentation_duration;
- *max_seg_duration /= 1000;
- *nb_segments = 1;
- return;
- }
if (rep->segment_list || set->segment_list || period->segment_list) {
GF_List *segments = NULL;
if (period->segment_list) {
@@ -454,6 +516,14 @@ static void gf_dash_get_segment_duration(GF_MPD_Representation *rep, GF_MPD_Adap
return;
}
+ /*single segment*/
+ if (rep->segment_base || set->segment_base || period->segment_base) {
+ *max_seg_duration = mpd->media_presentation_duration;
+ *max_seg_duration /= 1000;
+ *nb_segments = 1;
+ return;
+ }
+
single_segment = 1;
if (period->segment_template) {
single_segment = 0;
@@ -657,6 +727,10 @@ static void gf_dash_resolve_duration(GF_MPD_Representation *rep, GF_MPD_Adaptati
GF_MPD_SegmentTimelineEntry *ent = gf_list_get(segment_timeline->entries, 0);
if (ent) *out_duration = ent->duration;
}
+ else if (rep->segment_list) {
+ GF_MPD_SegmentURL *url = gf_list_get(rep->segment_list->segment_URLs, 0);
+ if (url && url->duration) *out_duration = url->duration;
+ }
}
static GF_Err gf_dash_merge_segment_timeline(GF_MPD_SegmentList *old_list, GF_MPD_SegmentTemplate *old_template, GF_MPD_SegmentList *new_list, GF_MPD_SegmentTemplate *new_template, Double min_start_time)
@@ -935,6 +1009,7 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash)
for (group_idx=0; group_idxgroups); group_idx++) {
GF_MPD_AdaptationSet *set, *new_set;
GF_DASH_Group *group = gf_list_get(dash->groups, group_idx);
+
if (group->selection != GF_DASH_GROUP_SELECTED) continue;
set = group->adaptation_set;
new_set = gf_list_get(new_period->adaptation_sets, group_idx);
@@ -1075,6 +1150,10 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash)
}
}
+ if (new_mpd->availabilityStartTime != dash->mpd->availabilityStartTime) {
+ gf_dash_group_timeline_setup(new_mpd, group);
+ }
+
/*update number of segments in active rep*/
gf_dash_get_segment_duration(gf_list_get(group->adaptation_set->representations, group->active_rep_index), group->adaptation_set, group->period, new_mpd, &group->nb_segments_in_rep, NULL);
@@ -1210,7 +1289,8 @@ typedef enum
} GF_DASHURLResolveType;
-GF_Err gf_dash_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_DASH_Group *group, char *mpd_url, GF_DASHURLResolveType resolve_type, u32 item_index, char **out_url, u64 *out_range_start, u64 *out_range_end, u64 *segment_duration)
+
+GF_Err gf_dash_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_DASH_Group *group, const char *mpd_url, GF_DASHURLResolveType resolve_type, u32 item_index, char **out_url, u64 *out_range_start, u64 *out_range_end, u64 *segment_duration, Bool *is_in_base_url)
{
GF_MPD_BaseURL *url_child;
GF_MPD_SegmentTimeline *timeline = NULL;
@@ -1225,6 +1305,15 @@ GF_Err gf_dash_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_DASH_Grou
*out_range_start = *out_range_end = 0;
*out_url = NULL;
+
+ if (!group->timeline_setup) {
+ gf_dash_group_timeline_setup(mpd, group);
+ group->timeline_setup = 1;
+ }
+
+
+
+
/*resolve base URLs from document base (download location) to representation (media)*/
url = gf_strdup(mpd_url);
@@ -1260,8 +1349,10 @@ GF_Err gf_dash_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_DASH_Grou
*segment_duration = (u32) ((Double) (*segment_duration) * 1000.0 / timescale);
/*single URL*/
- if (rep->segment_base || set->segment_base || period->segment_base) {
+// if (rep->segment_base || set->segment_base || period->segment_base) {
+ if (!rep->segment_list && !set->segment_list && !period->segment_list && !rep->segment_template && !set->segment_template && !period->segment_template) {
GF_MPD_URL *res_url;
+ GF_MPD_SegmentBase *base_seg = NULL;
if (item_index>0) return GF_EOS;
switch (resolve_type) {
case GF_DASH_RESOLVE_URL_MEDIA:
@@ -1271,29 +1362,32 @@ GF_Err gf_dash_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_DASH_Grou
case GF_DASH_RESOLVE_URL_INIT:
case GF_DASH_RESOLVE_URL_INDEX:
res_url = NULL;
- if (resolve_type == GF_DASH_RESOLVE_URL_INDEX) {
- if (period->segment_base) res_url = period->segment_base->representation_index;
- if (set->segment_base) res_url = set->segment_base->representation_index;
- if (rep->segment_base) res_url = rep->segment_base->representation_index;
- } else {
- if (period->segment_base) res_url = period->segment_base->initialization_segment;
- if (set->segment_base) res_url = set->segment_base->initialization_segment;
- if (rep->segment_base) res_url = rep->segment_base->initialization_segment;
- }
- /*no initialization segment / index*/
- if (!res_url) {
- gf_free(url);
- return GF_OK;
+ base_seg = rep->segment_base;
+ if (!base_seg) base_seg = set->segment_base;
+ if (!base_seg) base_seg = period->segment_base;
+
+ if (base_seg) {
+ if (resolve_type == GF_DASH_RESOLVE_URL_INDEX) {
+ res_url = base_seg->representation_index;
+ } else {
+ res_url = base_seg->initialization_segment;
+ }
}
- if (res_url->sourceURL) {
+ if (is_in_base_url) *is_in_base_url = 0;
+ /*no initialization segment / index, use base URL*/
+ if (res_url && res_url->sourceURL) {
*out_url = gf_url_concatenate(url, res_url->sourceURL);
gf_free(url);
} else {
*out_url = url;
+ if (is_in_base_url) *is_in_base_url = 1;
}
- if (res_url->byte_range) {
+ if (res_url && res_url->byte_range) {
*out_range_start = res_url->byte_range->start_range;
*out_range_end = res_url->byte_range->end_range;
+ } else if (base_seg && base_seg->index_range && (resolve_type == GF_DASH_RESOLVE_URL_INDEX)) {
+ *out_range_start = base_seg->index_range->start_range;
+ *out_range_end = base_seg->index_range->end_range;
}
return GF_OK;
default:
@@ -1374,6 +1468,9 @@ GF_Err gf_dash_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_DASH_Grou
*out_range_start = segment->media_range->start_range;
*out_range_end = segment->media_range->end_range;
}
+ if (segment->duration) {
+ *segment_duration = (u32) ((Double) (segment->duration) * 1000.0 / timescale);
+ }
return GF_OK;
case GF_DASH_RESOLVE_URL_INDEX:
if (item_index >= segment_count) {
@@ -1574,7 +1671,7 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group *
}
start_range = end_range = 0;
- e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration);
+ e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL);
if (e) {
gf_mx_v(dash->dl_mutex);
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Unable to resolve initialization URL: %s\n", gf_error_to_string(e) ));
@@ -1583,7 +1680,7 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group *
/*no error and no init segment, go for media segment*/
if (!base_init_url) {
- e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA, group->download_segment_index, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration);
+ e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA, group->download_segment_index, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL);
if (e) {
gf_mx_v(dash->dl_mutex);
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Unable to resolve media URL: %s\n", gf_error_to_string(e) ));
@@ -1594,7 +1691,7 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group *
group->dont_delete_first_segment = 1;
}
- if (!strstr(base_init_url, "://") || !strnicmp(base_init_url, "file://", 7) || !strnicmp(base_init_url, "views://", 8)) {
+ if (!strstr(base_init_url, "://") || !strnicmp(base_init_url, "file://", 7) || !strnicmp(base_init_url, "gmem://", 7) || !strnicmp(base_init_url, "views://", 8)) {
assert(!group->nb_cached_segments);
group->cached[0].cache = gf_strdup(base_init_url);
group->cached[0].url = gf_strdup(base_init_url);
@@ -1603,7 +1700,7 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group *
group->nb_cached_segments = 1;
/*do not erase local files*/
- group->local_files = 1;
+ group->local_files = group->was_segment_base ? 0 : 1;
group->download_segment_index += nb_segment_read;
group->segment_local_url = group->cached[0].cache;
group->local_url_start_range = start_range;
@@ -1623,11 +1720,11 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group *
if (a_rep==rep) continue;
if (a_rep->playback.disabled) continue;
- e = gf_dash_resolve_url(dash->mpd, a_rep, group, dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &a_base_init_url, &a_start, &a_end, &a_dur);
+ e = gf_dash_resolve_url(dash->mpd, a_rep, group, dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &a_base_init_url, &a_start, &a_end, &a_dur, NULL);
if (!e && a_base_init_url) {
a_rep->playback.cached_init_segment_url = a_base_init_url;
- rep->playback.init_start_range = a_start;
- rep->playback.init_end_range =a_end ;
+ a_rep->playback.init_start_range = a_start;
+ a_rep->playback.init_end_range =a_end ;
} else if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot solve initialization segment for representation: %s - discarding representation\n", gf_error_to_string(e) ));
a_rep->playback.disabled = 1;
@@ -1658,7 +1755,7 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group *
gf_free(base_init_url);
- e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA, group->download_segment_index + 1, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration);
+ e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA, group->download_segment_index + 1, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL);
if (!e) {
gf_mx_v(dash->dl_mutex);
return e;
@@ -1761,7 +1858,7 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group *
if (a_rep==rep) continue;
if (a_rep->playback.disabled) continue;
- e = gf_dash_resolve_url(dash->mpd, a_rep, group, dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &a_base_init_url, &a_start, &a_end, &a_dur);
+ e = gf_dash_resolve_url(dash->mpd, a_rep, group, dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &a_base_init_url, &a_start, &a_end, &a_dur, NULL);
if (!e && a_base_init_url) {
e = gf_dash_download_resource(dash->dash_io, &(group->segment_download), a_base_init_url, a_start, a_end, 1, group);
if (e) {
@@ -1769,8 +1866,8 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group *
a_rep->playback.disabled = 1;
} else {
a_rep->playback.cached_init_segment_url = gf_strdup( dash->dash_io->get_cache_name(dash->dash_io, group->segment_download) );
- rep->playback.init_start_range = 0;
- rep->playback.init_end_range = 0;
+ a_rep->playback.init_start_range = 0;
+ a_rep->playback.init_end_range = 0;
}
gf_free(a_base_init_url);
} else if (e) {
@@ -1882,8 +1979,14 @@ GF_Err gf_dash_setup_groups(GF_DashClient *dash)
for (j=0; jrepresentations); j++) {
Double dur;
u32 nb_seg;
- gf_dash_get_segment_duration(gf_list_get(set->representations, j), set, period, dash->mpd, &nb_seg, &dur);
+ GF_MPD_Representation *rep = gf_list_get(set->representations, j);
+ gf_dash_get_segment_duration(rep, set, period, dash->mpd, &nb_seg, &dur);
if (dur>seg_dur) seg_dur = dur;
+
+ if (rep->width>set->max_width) {
+ set->max_width = rep->width;
+ set->max_height = rep->height;
+ }
}
if (!seg_dur) {
@@ -1918,10 +2021,278 @@ GF_Err gf_dash_setup_groups(GF_DashClient *dash)
return GF_OK;
}
+static GF_Err gf_dash_load_sidx(GF_BitStream *bs, GF_MPD_Representation *rep, Bool seperate_index, u64 sidx_offset)
+{
+#ifdef GPAC_DISABLE_ISOM
+ return GF_NOT_SUPPORTED;
+#else
+ u64 anchor_position, prev_pos;
+ GF_SegmentIndexBox *sidx = NULL;
+ u32 i, size, type;
+ GF_Err e;
+ u64 offset;
+
+ prev_pos = gf_bs_get_position(bs);
+ gf_bs_seek(bs, sidx_offset);
+ size = gf_bs_read_u32(bs);
+ type = gf_bs_read_u32(bs);
+ if (type != GF_4CC('s','i','d','x')) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error parsing SIDX: type is %s (box start offset "LLD")\n", gf_4cc_to_str(type), gf_bs_get_position(bs)-8 ));
+ return GF_ISOM_INVALID_FILE;
+ }
+
+ gf_bs_seek(bs, sidx_offset);
+
+ anchor_position = sidx_offset + size;
+ if (seperate_index)
+ anchor_position = 0;
+
+ e = gf_isom_parse_box((GF_Box **) &sidx, bs);
+ if (e) return e;
+
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Loading SIDX - %d entries - Earliest Presentation Time "LLD"\n", sidx->nb_refs, sidx->earliest_presentation_time));
+
+ offset = sidx->first_offset + anchor_position;
+ rep->segment_list->timescale = sidx->timescale;
+ for (i=0; inb_refs; i++) {
+ GF_MPD_SegmentURL *seg;
+ if (sidx->refs[i].reference_type) {
+ e = gf_dash_load_sidx(bs, rep, seperate_index, offset);
+ if (e) {
+ break;
+ }
+ } else {
+ GF_SAFEALLOC(seg, GF_MPD_SegmentURL);
+ GF_SAFEALLOC(seg->media_range, GF_MPD_ByteRange);
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Found media segment size %d - duration %d - start with SAP: %d - SAP type %d - SAP Deltat Time %d\n",
+ sidx->refs[i].reference_size, sidx->refs[i].subsegment_duration, sidx->refs[i].starts_with_SAP, sidx->refs[i].SAP_type, sidx->refs[i].SAP_delta_time));
+
+ seg->media_range->start_range = offset;
+ offset += sidx->refs[i].reference_size;
+ seg->media_range->end_range = offset - 1;
+ seg->duration = sidx->refs[i].subsegment_duration;
+ gf_list_add(rep->segment_list->segment_URLs, seg);
+ }
+ }
+ gf_isom_box_del((GF_Box*)sidx);
+ gf_bs_seek(bs, prev_pos);
+ return e;
+#endif
+}
+
+static GF_Err gf_dash_load_representation_sidx(GF_DASH_Group *group, GF_MPD_Representation *rep, const char *cache_name, Bool seperate_index, Bool needs_mov_range)
+{
+ GF_Err e;
+ GF_BitStream *bs;
+ FILE *f=NULL;
+ if (!strncmp(cache_name, "gmem://", 7)) {
+ u32 size;
+ u8 *mem_address;
+ if (sscanf(cache_name, "gmem://%d@%p", &size, &mem_address) != 2) {
+ return GF_IO_ERR;
+ }
+ bs = gf_bs_new(mem_address, size, GF_BITSTREAM_READ);
+ } else {
+ FILE *f = gf_f64_open(cache_name, "rb");
+ if (!f) return GF_IO_ERR;
+ bs = gf_bs_from_file(f, GF_BITSTREAM_READ);
+ }
+ e = GF_OK;
+ while (gf_bs_available(bs)) {
+ u32 size = gf_bs_read_u32(bs);
+ u32 type = gf_bs_read_u32(bs);
+ if (type != GF_4CC('s','i','d','x')) {
+ gf_bs_skip_bytes(bs, size-8);
+
+ if (needs_mov_range && (type==GF_4CC('m','o','o','v') )) {
+ GF_SAFEALLOC(rep->segment_list->initialization_segment->byte_range, GF_MPD_ByteRange);
+ rep->segment_list->initialization_segment->byte_range->end_range = gf_bs_get_position(bs);
+ }
+ continue;
+ }
+ gf_bs_seek(bs, gf_bs_get_position(bs)-8);
+ e = gf_dash_load_sidx(bs, rep, seperate_index, gf_bs_get_position(bs) );
+
+ /*we could also parse the sub sidx*/
+ break;
+ }
+ gf_bs_del(bs);
+ if (f) fclose(f);
+ return e;
+}
+
+static GF_Err dash_load_box_type(const char *cache_name, u32 offset, u32 *box_type, u32 *box_size)
+{
+ *box_type = *box_size = 0;
+ if (!strncmp(cache_name, "gmem://", 7)) {
+ u32 size;
+ u8 *mem_address;
+ if (sscanf(cache_name, "gmem://%d@%p", &size, &mem_address) != 2) {
+ return GF_IO_ERR;
+ }
+ if (offset+8 > size)
+ return GF_IO_ERR;
+ mem_address+=offset;
+ *box_size = GF_4CC(mem_address[0], mem_address[1], mem_address[2], mem_address[3]);
+ *box_type = GF_4CC(mem_address[4], mem_address[5], mem_address[6], mem_address[7]);
+ } else {
+ unsigned char data[4];
+ FILE *f = gf_f64_open(cache_name, "rb");
+ if (!f) return GF_IO_ERR;
+ if (gf_f64_seek(f, offset, SEEK_SET))
+ return GF_IO_ERR;
+ if (fread(data, 1, 4, f) == 4) {
+ *box_size = GF_4CC(data[0], data[1], data[2], data[3]);
+ if (fread(data, 1, 4, f) == 4) {
+ *box_type = GF_4CC(data[0], data[1], data[2], data[3]);
+ }
+ }
+ fclose(f);
+ }
+ return GF_OK;
+}
+
+static GF_Err gf_dash_setup_single_index_mode(GF_DASH_Group *group)
+{
+ u32 i;
+ GF_Err e;
+ char *init_url = NULL;
+ char *index_url = NULL;
+ GF_MPD_Representation *rep = gf_list_get(group->adaptation_set->representations, 0);
+
+ if (rep->segment_template || group->adaptation_set->segment_template || group->period->segment_template) return GF_OK;
+ if (rep->segment_list || group->adaptation_set->segment_list || group->period->segment_list) return GF_OK;
+
+ /*OK we are in single-file mode, download all required indexes & co*/
+ for (i=0; iadaptation_set->representations); i++) {
+ char *sidx_file = NULL;
+ u64 duration, index_start_range, index_end_range, init_start_range, init_end_range;
+ Bool index_in_base, init_in_base;
+ Bool init_needs_byte_range = 0;
+ Bool has_seen_sidx = 0;
+ Bool is_isom = 1;
+ rep = gf_list_get(group->adaptation_set->representations, i);
+
+ index_in_base = init_in_base = 0;
+ e = gf_dash_resolve_url(group->dash->mpd, rep, group, group->dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &init_url, &init_start_range, &init_end_range, &duration, &init_in_base);
+ if (e) goto exit;
+
+ e = gf_dash_resolve_url(group->dash->mpd, rep, group, group->dash->base_url, GF_DASH_RESOLVE_URL_INDEX, 0, &index_url, &index_start_range, &index_end_range, &duration, &index_in_base);
+ if (e) goto exit;
+
+
+ if (is_isom && (init_in_base || index_in_base)) {
+ if (!strstr(init_url, "://") || (!strnicmp(init_url, "file://", 7) || !strnicmp(init_url, "views://", 7)) ) {
+ GF_SAFEALLOC(rep->segment_list, GF_MPD_SegmentList);
+ rep->segment_list->segment_URLs =gf_list_new();
+
+ if (init_in_base) {
+ GF_SAFEALLOC(rep->segment_list->initialization_segment, GF_MPD_URL);
+ rep->segment_list->initialization_segment->sourceURL = gf_strdup(init_url);
+ /*we don't want to load the entire movie */
+ init_needs_byte_range = 1;
+ }
+ if (index_in_base) {
+ sidx_file = (char *)init_url;
+ }
+ }
+ /*we need to download the init segement, at least partially*/
+ else {
+ u32 offset = 0;
+ u32 box_type=0;
+ u32 box_size=0;
+ const char *cache_name;
+
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Downloading init segment and SIDX for representation %s\n", init_url));
+
+ /*download first 8 bytes and check if we do have a box starting there*/
+ e = gf_dash_download_resource(group->dash->dash_io, &(group->segment_download), init_url, offset, 7, 1, group);
+ if (e) goto exit;
+ cache_name = group->dash->dash_io->get_cache_name(group->dash->dash_io, group->segment_download);
+ e = dash_load_box_type(cache_name, offset, &box_type, &box_size);
+ offset=8;
+ while (box_type) {
+ /*we got the moov , stop here */
+ if (!index_in_base && (box_type==GF_4CC('m','o','o','v'))) {
+ e = gf_dash_download_resource(group->dash->dash_io, &(group->segment_download), init_url, offset, offset+box_size-8, 2, group);
+ break;
+ } else {
+ e = gf_dash_download_resource(group->dash->dash_io, &(group->segment_download), init_url, offset, offset+box_size-1, 2, group);
+ offset += box_size;
+ /*we need to refresh the cache name because of our memory astorage thing ...*/
+ cache_name = group->dash->dash_io->get_cache_name(group->dash->dash_io, group->segment_download);
+ e = dash_load_box_type(cache_name, offset-8, &box_type, &box_size);
+
+ if (box_type==GF_4CC('s','i','d','x'))
+ has_seen_sidx = 1;
+ else if (has_seen_sidx)
+ break;
+
+
+ }
+ }
+ if (e<0) goto exit;
+
+ if (box_type==0) {
+ e = GF_ISOM_INVALID_FILE;
+ goto exit;
+ }
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Done downloading init segment and SIDX\n"));
+
+ GF_SAFEALLOC(rep->segment_list, GF_MPD_SegmentList);
+ rep->segment_list->segment_URLs =gf_list_new();
+
+ cache_name = group->dash->dash_io->get_cache_name(group->dash->dash_io, group->segment_download);
+ if (init_in_base) {
+ GF_SAFEALLOC(rep->segment_list->initialization_segment, GF_MPD_URL);
+ rep->segment_list->initialization_segment->sourceURL = gf_strdup(cache_name);
+ }
+ if (index_in_base) {
+ sidx_file = (char *)cache_name;
+ }
+ }
+ }
+ /*we have index url, download it*/
+ if (! index_in_base) {
+ e = gf_dash_download_resource(group->dash->dash_io, &(group->segment_download), index_url, index_start_range, index_end_range, 1, group);
+ if (e) goto exit;
+ sidx_file = (char *)group->dash->dash_io->get_cache_name(group->dash->dash_io, group->segment_download);
+ }
+
+ /*load sidx*/
+ e = gf_dash_load_representation_sidx(group, rep, sidx_file, !index_in_base, init_needs_byte_range);
+ if (e) {
+ rep->playback.disabled = 1;
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Failed to load segment index for this representation - disabling\n"));
+ }
+
+ /*reset all seg based stuff*/
+ if (rep->segment_base) {
+ gf_mpd_segment_base_free(rep->segment_base);
+ rep->segment_base = NULL;
+ }
+
+ gf_free(index_url);
+ index_url = NULL;
+ gf_free(init_url);
+ init_url = NULL;
+ }
+ if (group->adaptation_set->segment_base) {
+ gf_mpd_segment_base_free(group->adaptation_set->segment_base);
+ group->adaptation_set->segment_base = NULL;
+ }
+ group->was_segment_base = 1;
+
+exit:
+ if (init_url) gf_free(init_url);
+ if (index_url) gf_free(index_url);
+ return e;
+}
+
static GF_Err gf_dash_setup_period(GF_DashClient *dash)
{
+ GF_MPD_Period *period;
u32 rep_i, group_i, nb_groups_ok;
-
/*setup all groups*/
gf_dash_setup_groups(dash);
@@ -1930,6 +2301,7 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash)
GF_MPD_Representation *rep_sel;
u32 active_rep, nb_rep;
const char *mime_type;
+ u32 nb_rep_ok = 0;
GF_DASH_Group *group = gf_list_get(dash->groups, group_i);
nb_rep = gf_list_count(group->adaptation_set->representations);
@@ -1943,6 +2315,9 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash)
continue;
}
+ /*translate from single-indexed file to SegmentList*/
+ gf_dash_setup_single_index_mode(group);
+
/* Select the appropriate representation in the given period */
active_rep = 0;
for (rep_i = 0; rep_i < nb_rep; rep_i++) {
@@ -1952,7 +2327,8 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash)
if (rep_i) {
Bool ok;
char *sep;
- if ( !rep->codecs || !rep_sel->codecs ) continue;
+ if ( !rep->codecs || !rep_sel->codecs) continue;
+
sep = strchr(rep_sel->codecs, '.');
if (sep) sep[0] = 0;
ok = !strnicmp(rep->codecs, rep_sel->codecs, strlen(rep_sel->codecs) );
@@ -1986,10 +2362,11 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash)
}
break;
case GF_DASH_SELECT_QUALITY_HIGHEST:
+ /*fallthrough if quality is not indicated*/
if (rep->quality_ranking > rep_sel->quality_ranking) {
active_rep = rep_i;
break;
- }/*fallthrough if quality is not indicated*/
+ }
case GF_DASH_SELECT_BANDWIDTH_HIGHEST:
if (rep->bandwidth > rep_sel->bandwidth) {
active_rep = rep_i;
@@ -1999,8 +2376,20 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash)
break;
}
}
+ for (rep_i = 0; rep_i < nb_rep; rep_i++) {
+ GF_MPD_Representation *rep = gf_list_get(group->adaptation_set->representations, rep_i);
+ if (!rep->playback.disabled)
+ nb_rep_ok++;
+ }
+
+ if (! nb_rep_ok) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] No valid representation in this group - disabling\n"));
+ group->selection = GF_DASH_GROUP_NOT_SELECTABLE;
+ continue;
+ }
rep_sel = gf_list_get(group->adaptation_set->representations, active_rep);
+
gf_dash_set_group_representation(group, rep_sel);
if (dash->playback_start_range>=0)
@@ -2026,6 +2415,14 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash)
group->selection = GF_DASH_GROUP_NOT_SELECTED;
nb_groups_ok++;
}
+
+ period = gf_list_get(dash->mpd->periods, dash->active_period_index);
+
+ if (period->segment_base) {
+ gf_mpd_segment_base_free(period->segment_base);
+ period->segment_base = NULL;
+ }
+
if (!nb_groups_ok) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] No AdaptationSet could be selected in the MPD - Cannot play\n"));
return GF_NON_COMPLIANT_BITSTREAM;
@@ -2059,6 +2456,14 @@ restart_period:
dash->in_period_setup = 1;
+ /*setup period*/
+ e = gf_dash_setup_period(dash);
+ if (e) {
+ dash->dash_io->on_dash_event(dash->dash_io, GF_DASH_EVENT_PERIOD_SETUP_ERROR, e);
+ ret = 1;
+ goto exit;
+ }
+
dash->dash_io->on_dash_event(dash->dash_io, GF_DASH_EVENT_SELECT_GROUPS, GF_OK);
e = GF_OK;
@@ -2108,9 +2513,8 @@ restart_period:
/*wait until next segment is needed*/
while (!dash->mpd_stop_request) {
u32 timer = gf_sys_clock() - dash->last_update_time;
- Bool shouldParsePlaylist = dash->mpd->minimum_update_period && (timer > dash->mpd->minimum_update_period);
- if (shouldParsePlaylist) {
+ if (dash->mpd->minimum_update_period && (timer > dash->mpd->minimum_update_period)) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Time to update the playlist (%u ms ellapsed since last refresh and min reoad rate is %u)\n", timer, dash->mpd->minimum_update_period));
e = gf_dash_update_manifest(dash);
group_count = gf_list_count(dash->groups);
@@ -2140,13 +2544,12 @@ restart_period:
if (dash->request_period_switch == 1)
dash->active_period_index++;
- gf_dash_setup_period(dash);
dash->request_period_switch = 0;
goto restart_period;
}
- gf_sleep(16);
+ gf_sleep(30);
}
}
@@ -2178,8 +2581,16 @@ restart_period:
we need to check if a new playlist is ready */
if (group->nb_segments_in_rep && (group->download_segment_index>=group->nb_segments_in_rep)) {
u32 timer = gf_sys_clock() - dash->last_update_time;
+ Bool update_playlist = 0;
/* update of the playlist, only if indicated */
- if (dash->mpd->minimum_update_period && timer > dash->mpd->minimum_update_period) {
+ if (dash->mpd->minimum_update_period && (timer > dash->mpd->minimum_update_period)) {
+ update_playlist = 1;
+ }
+ /* if media_presentation_duration is 0 and we are in live, force a refresh (not in the spec but safety check*/
+ else if ((dash->mpd->type==GF_MPD_TYPE_DYNAMIC) && !dash->mpd->media_presentation_duration) {
+ update_playlist = 1;
+ }
+ if (update_playlist) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Last segment in current playlist downloaded, checking updates after %u ms\n", timer));
e = gf_dash_update_manifest(dash);
if (e) {
@@ -2192,8 +2603,8 @@ restart_period:
}
/* Now that the playlist is up to date, we can check again */
if (group->download_segment_index >= group->nb_segments_in_rep) {
- if (dash->mpd->minimum_update_period) {
- /* if there is a specified update period, we redo the whole process */
+ /* if there is a specified update period, we redo the whole process */
+ if (dash->mpd->minimum_update_period ) {
continue;
} else {
/* if not, we are really at the end of the playlist, we can quit */
@@ -2205,10 +2616,16 @@ restart_period:
}
gf_mx_p(dash->dl_mutex);
- /*todo for live - check we don't attempt to request segments before their availabilityStartTime !*/
+ if (group->force_switch_bandwidth && !dash->auto_switch_count) {
+ gf_dash_switch_group_representation(dash, group);
+ /*restart*/
+ i--;
+ gf_mx_v(dash->dl_mutex);
+ continue;
+ }
/* At this stage, there are some segments left to be downloaded */
- e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA, group->download_segment_index, &new_base_seg_url, &start_range, &end_range, &group->current_downloaded_segment_duration);
+ e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA, group->download_segment_index, &new_base_seg_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL);
gf_mx_v(dash->dl_mutex);
if (e) {
/*do something!!*/
@@ -2221,7 +2638,7 @@ restart_period:
}
/*local file*/
- if (!strstr(new_base_seg_url, "://") || !strnicmp(new_base_seg_url, "file://", 7)) {
+ if (!strstr(new_base_seg_url, "://") || (!strnicmp(new_base_seg_url, "file://", 7) || !strnicmp(new_base_seg_url, "gmem://", 7)) ) {
resource_name = local_file_name = (char *) new_base_seg_url;
e = GF_OK;
/*do not erase local files*/
@@ -2565,7 +2982,6 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url)
GF_Err e;
GF_MPD_Period *period;
GF_DOMParser *mpd_parser;
- Bool is_m3u8 = 0;
Bool is_local = 0;
if (!dash || !manifest_url) return GF_BAD_PARAM;
@@ -2592,7 +3008,7 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url)
local_url = manifest_url + 7;
is_local = 1;
if (strstr(manifest_url, ".m3u8")) {
- is_m3u8 = 1;
+ dash->is_m3u8 = 1;
}
} else if (strstr(manifest_url, "://")) {
const char *reloc_url, *mtype;
@@ -2612,7 +3028,7 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url)
reloc_url = dash->dash_io->get_url(dash->dash_io, dash->mpd_dnload);
/* Some servers, for instance http://tv.freebox.fr, serve m3u8 as text/plain */
if (gf_dash_is_m3u8_mime(mime) || strstr(reloc_url, ".m3u8") || strstr(reloc_url, ".M3U8")) {
- is_m3u8 = 1;
+ dash->is_m3u8 = 1;
} else if (!gf_dash_is_dash_mime(mime) && !strstr(reloc_url, ".mpd") && !strstr(reloc_url, ".MPD")) {
GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] mime '%s' for '%s' should be m3u8 or mpd\n", mime, reloc_url));
dash->dash_io->del(dash->dash_io, dash->mpd_dnload);
@@ -2631,7 +3047,7 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url)
local_url = manifest_url;
is_local = 1;
if (strstr(manifest_url, ".m3u8"))
- is_m3u8 = 1;
+ dash->is_m3u8 = 1;
}
if (is_local) {
@@ -2640,7 +3056,7 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url)
fclose(f);
}
- if (is_m3u8) {
+ if (dash->is_m3u8) {
if (is_local) {
char *sep;
strcpy(local_path, local_url);
@@ -2707,11 +3123,8 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url)
goto exit;
}
- e = gf_dash_setup_period(dash);
- if (e) goto exit;
-
e = gf_th_run(dash->dash_thread, dash_main_thread_proc, dash);
- gf_sleep(0);
+
return e;
exit:
dash->dash_io->del(dash->dash_io, dash->mpd_dnload);
@@ -2754,7 +3167,7 @@ GF_DashClient *gf_dash_new(GF_DASHFileIO *dash_io, u32 max_cache_duration_sec, u
dash->dash_thread = gf_th_new("MPD Segment Downloader Thread");
dash->dl_mutex = gf_mx_new("MPD Segment Downloader Mutex");
- dash->mimeTypeForM3U8Segments = gf_strdup( M3U8_UNKOWN_MIME_TYPE );
+ dash->mimeTypeForM3U8Segments = gf_strdup( "video/mp2t" );
dash->max_cache_duration = max_cache_duration_sec;
@@ -2823,46 +3236,67 @@ void gf_dash_get_info(GF_DashClient *dash, const char **title, const char **sour
}
GF_EXPORT
-void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up)
+void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up, Bool immediate_switch)
{
u32 i;
for (i=0; igroups); i++) {
- Bool do_switch = 0;
+ u32 switch_to_rep_idx = 0;
+ u32 bandwidth, quality, k;
+ GF_MPD_Representation *rep, *active_rep;
GF_DASH_Group *group = gf_list_get(dash->groups, i);
u32 current_idx = group->active_rep_index;
if (group->selection != GF_DASH_GROUP_SELECTED) continue;
if (group->force_representation_idx_plus_one) current_idx = group->force_representation_idx_plus_one - 1;
- if (switch_up) {
- if (current_idx + 1 < gf_list_count(group->adaptation_set->representations)) {
- group->force_representation_idx_plus_one = 1 + current_idx+1;
- do_switch = 1;
- }
- } else {
- if (current_idx) {
- group->force_representation_idx_plus_one = 1 + current_idx - 1;
- do_switch = 1;
+
+ active_rep = gf_list_get(group->adaptation_set->representations, current_idx);
+ if (!active_rep) continue;
+ bandwidth = switch_up ? (u32) -1 : 0;
+ quality = switch_up ? (u32) -1 : 0;
+
+ for (k=0; kadaptation_set->representations); k++) {
+ rep = gf_list_get(group->adaptation_set->representations, k);
+ if (switch_up) {
+ if ((rep->quality_ranking>active_rep->quality_ranking) || (rep->bandwidth>active_rep->bandwidth)) {
+ if ((rep->quality_ranking < quality) || (rep->bandwidth < bandwidth)) {
+ bandwidth = rep->bandwidth;
+ quality = rep->quality_ranking;
+ switch_to_rep_idx = k+1;
+ }
+ }
+ } else {
+ if ((rep->quality_ranking < active_rep->quality_ranking) || (rep->bandwidth < active_rep->bandwidth)) {
+ if ((rep->quality_ranking > quality) || (rep->bandwidth > bandwidth)) {
+ bandwidth = rep->bandwidth;
+ quality = rep->quality_ranking;
+ switch_to_rep_idx = k+1;
+ }
+ }
}
}
- if (do_switch) {
+ if (switch_to_rep_idx && (switch_to_rep_idx-1 != current_idx) ) {
gf_mx_p(dash->dl_mutex);
group->force_switch_bandwidth = 1;
- /*in local playback just switch at the end of the current segment
- for remote, we should let the user decide*/
- while (group->nb_cached_segments>1) {
- group->nb_cached_segments--;
- gf_free(group->cached[group->nb_cached_segments].url);
- group->cached[group->nb_cached_segments].url = NULL;
- if (!group->local_files && group->cached[group->nb_cached_segments].cache) {
- gf_delete_file( group->cached[group->nb_cached_segments].cache );
- gf_free(group->cached[group->nb_cached_segments].cache);
- group->cached[group->nb_cached_segments].cache = NULL;
+ group->force_representation_idx_plus_one = switch_to_rep_idx;
+
+ if (group->local_files || immediate_switch) {
+ /*in local playback just switch at the end of the current segment
+ for remote, we should let the user decide*/
+ while (group->nb_cached_segments>1) {
+ group->nb_cached_segments--;
+ gf_free(group->cached[group->nb_cached_segments].url);
+ group->cached[group->nb_cached_segments].url = NULL;
+ if (!group->local_files && group->cached[group->nb_cached_segments].cache) {
+ gf_delete_file( group->cached[group->nb_cached_segments].cache );
+ gf_free(group->cached[group->nb_cached_segments].cache);
+ group->cached[group->nb_cached_segments].cache = NULL;
+ }
+ group->cached[group->nb_cached_segments].representation_index = 0;
+ group->cached[group->nb_cached_segments].start_range = 0;
+ group->cached[group->nb_cached_segments].end_range = 0;
+ if (group->download_segment_index>1)
+ group->download_segment_index--;
}
- group->cached[group->nb_cached_segments].representation_index = 0;
- group->cached[group->nb_cached_segments].start_range = 0;
- group->cached[group->nb_cached_segments].end_range = 0;
- assert(group->download_segment_index>1);
- group->download_segment_index--;
}
gf_mx_v(dash->dl_mutex);
}
@@ -3075,7 +3509,7 @@ GF_Err gf_dash_group_get_presentation_time_offset(GF_DashClient *dash, u32 idx,
}
GF_EXPORT
-GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, const char **url, u64 *start_range, u64 *end_range, const char **switching_url, u64 *switching_start_range, u64 *switching_end_range, const char **original_url)
+GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, const char **url, u64 *start_range, u64 *end_range, s32 *switching_index, const char **switching_url, u64 *switching_start_range, u64 *switching_end_range, const char **original_url)
{
GF_DASH_Group *group;
@@ -3086,6 +3520,7 @@ GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, con
if (switching_start_range) *switching_start_range = 0;
if (switching_end_range) *switching_end_range = 0;
if (original_url) *original_url = NULL;
+ if (switching_index) *switching_index = -1;
gf_mx_p(dash->dl_mutex);
group = gf_list_get(dash->groups, idx);
@@ -3102,6 +3537,8 @@ GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, con
if (group->cached[0].representation_index != group->prev_active_rep_index) {
GF_MPD_Representation *rep = gf_list_get(group->adaptation_set->representations, group->cached[0].representation_index);
+ if (switching_index)
+ *switching_index = group->cached[0].representation_index;
if (switching_start_range)
*switching_start_range = rep->playback.init_start_range;
if (switching_end_range)
@@ -3149,5 +3586,35 @@ Double gf_dash_group_current_segment_start_time(GF_DashClient *dash, u32 idx)
return gf_dash_get_segment_start_time(group);
}
+GF_EXPORT
+GF_Err gf_dash_group_get_video_info(GF_DashClient *dash, u32 idx, u32 *max_width, u32 *max_height)
+{
+ GF_DASH_Group *group = gf_list_get(dash->groups, idx);
+ if (!group || !max_width || !max_height) return GF_BAD_PARAM;
+
+ *max_width = group->adaptation_set->max_width;
+ *max_height = group->adaptation_set->max_height;
+ return GF_OK;
+}
+
+GF_EXPORT
+GF_Err gf_dash_group_get_representation_info(GF_DashClient *dash, u32 idx, u32 representation_idx, u32 *width, u32 *height, u32 *audio_samplerate, u32 *bandwidth, const char **codecs)
+{
+ GF_DASH_Group *group = gf_list_get(dash->groups, idx);
+ GF_MPD_Representation *rep;
+ if (!group) return GF_BAD_PARAM;
+ rep = gf_list_get(group->adaptation_set->representations, representation_idx);
+ if (!rep) return GF_BAD_PARAM;
+
+ if (width) *width = rep->width ? rep->width : group->adaptation_set->width;
+ if (height) *width = rep->height ? rep->height : group->adaptation_set->height;
+ if (codecs) *codecs = rep->codecs ? rep->codecs : group->adaptation_set->codecs;
+ if (bandwidth) *bandwidth = rep->bandwidth;
+ if (audio_samplerate) *audio_samplerate = rep->samplerate ? rep->samplerate : group->adaptation_set->samplerate;
+
+ return GF_OK;
+}
+
+
#endif //GPAC_DISABLE_DASH_CLIENT
diff --git a/src/media_tools/dash_segmenter.c b/src/media_tools/dash_segmenter.c
index f82e725..476f274 100644
--- a/src/media_tools/dash_segmenter.c
+++ b/src/media_tools/dash_segmenter.c
@@ -52,7 +52,7 @@ struct _dash_component
/*for audio*/
u32 sample_rate, channels;
/*for anything*/
- char szLang[4];
+ char szLang[5];
};
typedef struct
@@ -68,6 +68,7 @@ typedef struct
s32 time_shift_depth;
Double subduration;
const char *bs_switch_segment_file;
+ Bool inband_param_set;
/*set if seg_rad_name depends on input file name (had %s in it). In this case, SegmentTemplate cannot be used at adaptation set level*/
Bool variable_seg_rad_name;
@@ -85,6 +86,7 @@ struct _dash_segment_input
char *file_name;
char representationID[100];
char periodID[100];
+ char role[100];
u32 bandwidth;
/*if 0, input is disabled*/
@@ -100,7 +102,7 @@ struct _dash_segment_input
/*assigns the different media to the same adaptation set or group than the input_idx one*/
GF_Err (* dasher_input_classify) (GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 input_idx, u32 *current_group_id, u32 *max_sap_type);
GF_Err ( *dasher_get_components_info) (GF_DashSegInput *dash_input, GF_DASHSegmenterOptions *opts);
- GF_Err ( *dasher_create_init_segment) (GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 adaptation_set, char *szInitName, const char *tmpdir, Bool *disable_bs_switching);
+ GF_Err ( *dasher_create_init_segment) (GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 adaptation_set, char *szInitName, const char *tmpdir, Bool use_inband_param_set, Bool *disable_bs_switching);
GF_Err ( *dasher_segment_file) (GF_DashSegInput *dash_input, const char *szOutName, GF_DASHSegmenterOptions *opts, Bool first_in_set);
/*shall be set after call to dasher_input_classify*/
@@ -285,6 +287,8 @@ GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCo
case GF_ISOM_SUBTYPE_AVC_H264:
case GF_ISOM_SUBTYPE_AVC2_H264:
+ case GF_ISOM_SUBTYPE_AVC3_H264:
+ case GF_ISOM_SUBTYPE_AVC4_H264:
case GF_ISOM_SUBTYPE_SVC_H264:
avcc = gf_isom_avc_config_get(movie, track, 1);
sps = gf_list_get(avcc->sequenceParameterSets, 0);
@@ -315,7 +319,7 @@ typedef struct
Bool done;
u32 TrackID;
u32 SampleNum, SampleCount;
- u32 FragmentLength;
+ u64 FragmentLength;
u32 OriginalTrack;
u32 finalSampleDescriptionIndex;
u32 TimeScale, MediaType, DefaultDuration, InitialTSOffset;
@@ -363,7 +367,7 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f
GF_ISOFile *output, *bs_switch_segment;
GF_ISOSample *sample, *next;
GF_List *fragmenters;
- u32 MaxFragmentDuration, MaxSegmentDuration, SegmentDuration, maxFragDurationOverSegment;
+ u64 MaxFragmentDuration, MaxSegmentDuration, SegmentDuration, maxFragDurationOverSegment;
u32 presentationTimeOffset = 0;
Double segment_start_time, file_duration, period_duration, max_segment_duration;
u32 nb_segments, width, height, sample_rate, nb_channels, sar_w, sar_h, fps_num, fps_denum, startNumber, startNumberRewind;
@@ -383,7 +387,8 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f
u32 tfref_timescale = 0;
u32 bandwidth = 0;
GF_ISOMTrackFragmenter *tf, *tfref;
- FILE *mpd_segs = NULL;
+ GF_BitStream *mpd_bs = NULL;
+ char szMPDTempLine[2048];
char SegmentName[GF_MAX_PATH];
char RepSecName[200];
char RepURLsSecName[200];
@@ -503,12 +508,12 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f
opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "Bandwidth");
if (opt) sscanf(opt, "%u", &bandwidth);
}
- mpd_segs = gf_temp_file_new();
+ mpd_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
} else {
output = gf_isom_open(output_file, GF_ISOM_OPEN_WRITE, NULL);
if (!output) return gf_isom_last_error(NULL);
}
-
+
nb_sync = 0;
nb_samp = 0;
fragmenters = gf_list_new();
@@ -561,6 +566,7 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f
if (mtype == GF_ISOM_MEDIA_HINT) continue;
if (! dash_moov_setup) {
+ u32 avctype;
e = gf_isom_clone_track(input, i+1, output, 0, &TrackNum);
if (e) goto err_exit;
@@ -576,6 +582,16 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f
continue;
}
+ avctype = gf_isom_get_avc_svc_type(input, i+1, 1);
+ if (avctype==GF_ISOM_AVCTYPE_AVC_ONLY) {
+ /*for AVC we concatenate SPS/PPS*/
+ if (dash_cfg->inband_param_set)
+ gf_isom_set_nalu_extract_mode(input, i+1, GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG);
+ }
+ else if (avctype > GF_ISOM_AVCTYPE_AVC_ONLY) {
+ /*for SVC we don't want any rewrite of extractors, and we don't concatenate SPS/PPS*/
+ gf_isom_set_nalu_extract_mode(input, i+1, GF_ISOM_NALU_EXTRACT_INSPECT);
+ }
} else {
TrackNum = gf_isom_get_track_by_id(output, gf_isom_get_track_id(input, i+1));
count = gf_isom_get_sample_count(input, i+1);
@@ -824,7 +840,8 @@ restart_fragmentation_pass:
for (i=0; idash_ctx, RepURLsSecName, i);
opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepURLsSecName, key_name);
- fprintf(mpd_segs, " %s\n", opt);
+ sprintf(szMPDTempLine, " %s\n", opt);
+ gf_bs_write_data(mpd_bs, szMPDTempLine, strlen(szMPDTempLine));
}
opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "NextSegmentIndex");
@@ -834,18 +851,21 @@ restart_fragmentation_pass:
opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "CumulatedDuration");
if (opt) period_duration = atof(opt);
- sprintf(sKey, "TKID_%d_NextSampleNum", tf->TrackID);
- opt = (char *)gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, sKey);
- if (opt) tf->SampleNum = atoi(opt);
+ for (i=0; iTrackID);
+ opt = (char *)gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, sKey);
+ if (opt) tf->SampleNum = atoi(opt);
- sprintf(sKey, "TKID_%d_LastSampleCTS", tf->TrackID);
- opt = (char *)gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, sKey);
- if (opt) sscanf(opt, LLU, &tf->last_sample_cts);
+ sprintf(sKey, "TKID_%d_LastSampleCTS", tf->TrackID);
+ opt = (char *)gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, sKey);
+ if (opt) sscanf(opt, LLU, &tf->last_sample_cts);
- sprintf(sKey, "TKID_%d_NextSampleDTS", tf->TrackID);
- opt = (char *)gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, sKey);
- if (opt) {
- sscanf(opt, LLU, &tf->next_sample_dts);
+ sprintf(sKey, "TKID_%d_NextSampleDTS", tf->TrackID);
+ opt = (char *)gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, sKey);
+ if (opt) {
+ sscanf(opt, LLU, &tf->next_sample_dts);
+ }
}
}
gf_isom_set_next_moof_number(output, fragment_index);
@@ -886,7 +906,8 @@ restart_fragmentation_pass:
if (!use_url_template) {
const char *name = gf_url_get_resource_name(SegmentName);
- fprintf(mpd_segs, " \n", name );
+ sprintf(szMPDTempLine, " \n", name );
+ gf_bs_write_data(mpd_bs, szMPDTempLine, strlen(szMPDTempLine));
if (dash_cfg->dash_ctx) {
char szKey[100], szVal[4046];
sprintf(szKey, "UrlInfo%d", cur_seg );
@@ -988,11 +1009,11 @@ restart_fragmentation_pass:
if (tf->splitable) {
if (tfref==tf) {
- u32 frag_dur = (tf->FragmentLength + defaultDuration) * 1000 / tf->TimeScale;
+ u64 frag_dur = (tf->FragmentLength + defaultDuration) * 1000 / tf->TimeScale;
/*if media segment about to be produced is longer than max segment length, force segment split*/
if (SegmentDuration + frag_dur > MaxSegmentDuration) {
split_sample_duration = defaultDuration;
- defaultDuration = tf->TimeScale * (MaxSegmentDuration - SegmentDuration) / 1000 - tf->FragmentLength;
+ defaultDuration = (u32) (tf->TimeScale * (MaxSegmentDuration - SegmentDuration) / 1000 - tf->FragmentLength);
split_sample_duration -= defaultDuration;
}
} else if ((tf->last_sample_cts + defaultDuration) * tfref_timescale > tfref->next_sample_dts * tf->TimeScale) {
@@ -1083,7 +1104,7 @@ restart_fragmentation_pass:
}
else if (split_seg_at_rap) {
u64 next_sap_time;
- u32 frag_dur, next_dur;
+ u64 frag_dur, next_dur;
next_dur = gf_isom_get_sample_duration(input, tf->OriginalTrack, tf->SampleNum + 1);
if (!next_dur) next_dur = defaultDuration;
/*duration of fragment if we add this rap*/
@@ -1177,7 +1198,7 @@ restart_fragmentation_pass:
segment_start_time += SegmentDuration;
nb_segments++;
if (max_segment_duration * 1000 <= SegmentDuration) {
- max_segment_duration = SegmentDuration;
+ max_segment_duration = (Double) (s64) SegmentDuration;
max_segment_duration /= 1000;
}
force_switch_segment=0;
@@ -1198,11 +1219,14 @@ restart_fragmentation_pass:
file_size = gf_isom_get_file_size(output);
end_range = file_size - 1;
if (dash_cfg->single_file_mode!=1) {
- fprintf(mpd_segs, " \n");
+ gf_bs_write_data(mpd_bs, "/>\n", 3);
+
if (dash_cfg->dash_ctx) {
char szKey[100], szVal[4046];
sprintf(szKey, "UrlInfo%d", cur_seg );
@@ -1246,14 +1270,12 @@ restart_fragmentation_pass:
}
if (dash_cfg) {
- char buffer[1000];
-
/*flush last segment*/
if (!switch_segment) {
u64 idx_start_range, idx_end_range;
if (max_segment_duration * 1000 <= SegmentDuration) {
- max_segment_duration = SegmentDuration;
+ max_segment_duration = (Double) (s64) SegmentDuration;
max_segment_duration /= 1000;
}
@@ -1266,11 +1288,13 @@ restart_fragmentation_pass:
file_size = gf_isom_get_file_size(output);
end_range = file_size - 1;
if (dash_cfg->single_file_mode!=1) {
- fprintf(mpd_segs, " \n");
+ gf_bs_write_data(mpd_bs, "/>\n", 3);
if (dash_cfg->dash_ctx) {
char szKey[100], szVal[4046];
@@ -1405,11 +1429,12 @@ restart_fragmentation_pass:
fprintf(dash_cfg->mpd, "/>\n");
}
}
-
- gf_f64_seek(mpd_segs, 0, SEEK_SET);
- while (!feof(mpd_segs)) {
- u32 r = fread(buffer, 1, 100, mpd_segs);
- gf_fwrite(buffer, 1, r, dash_cfg->mpd);
+ if (mpd_bs) {
+ char *mpd_seg_info = NULL;
+ u32 size;
+ gf_bs_get_content(mpd_bs, &mpd_seg_info, &size);
+ gf_fwrite(mpd_seg_info, 1, size, dash_cfg->mpd);
+ gf_free(mpd_seg_info);
}
if (!use_url_template && (dash_cfg->single_file_mode!=1)) {
@@ -1480,7 +1505,7 @@ err_exit:
if (!bs_switching_is_output && bs_switch_segment)
gf_isom_delete(bs_switch_segment);
gf_set_progress("ISO File Fragmenting", nb_samp, nb_samp);
- if (mpd_segs) fclose(mpd_segs);
+ if (mpd_bs) gf_bs_del(mpd_bs);
return e;
}
@@ -1544,6 +1569,9 @@ static GF_Err dasher_isom_classify_input(GF_DashSegInput *dash_inputs, u32 nb_da
if (strcmp(dash_inputs[input_idx].szMime, dash_inputs[i].szMime))
continue;
+ if (strcmp(dash_inputs[input_idx].role, dash_inputs[i].role))
+ continue;
+
in = gf_isom_open(dash_inputs[i].file_name, GF_ISOM_OPEN_READ, NULL);
for (j=0; jsequenceParameterSets, l);
gf_avc_get_sps_info(slc_orig->data, slc_orig->size, &sps_id2, NULL, NULL, NULL, NULL);
if (sps_id2==sps_id1) {
- do_merge = 0;
+ merge_mode = 0;
break;
}
}
}
#endif
/*no conflicts in SPS ids, merge all SPS in a single sample desc*/
- if (do_merge) {
+ if (merge_mode==1) {
while (gf_list_count(avccfg1->sequenceParameterSets)) {
GF_AVCConfigSlot *slc = gf_list_get(avccfg1->sequenceParameterSets, 0);
gf_list_rem(avccfg1->sequenceParameterSets, 0);
@@ -1721,7 +1759,7 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32
}
/*cannot merge, clone*/
- if (!do_merge)
+ if (merge_mode==0)
gf_isom_clone_sample_description(init_seg, track, in, j+1, 1, NULL, NULL, &outDescIndex);
}
} else {
@@ -1731,6 +1769,18 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32
gf_isom_clone_track(in, j+1, init_seg, 0, &track);
+ switch (gf_isom_get_media_subtype(in, j+1, 1)) {
+ case GF_4CC( 'a', 'v', 'c', '1'):
+ case GF_4CC( 'a', 'v', 'c', '2'):
+ case GF_4CC( 's', 'v', 'c', '1'):
+ if (use_inband_param_set) {
+ gf_isom_avc_set_inband_config(init_seg, track, 1);
+ use_avc3 = 1;
+ }
+ break;
+ }
+
+
gf_isom_get_fragment_defaults(in, j+1, &defaultDuration, &defaultSize,
&defaultDescriptionIndex, &defaultRandomAccess,
&defaultPadding, &defaultDegradationPriority);
@@ -1740,11 +1790,18 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32
defaultSize, (u8) defaultRandomAccess,
defaultPadding, defaultDegradationPriority);
if (e) break;
+
+ }
+ }
+ if (!i) {
+ if (use_avc3) {
+ gf_isom_set_brand_info(init_seg, GF_4CC('i','s','o','6'), 1);
+ } else {
+ gf_isom_set_brand_info(init_seg, GF_4CC('i','s','o','5'), 1);
}
+ gf_isom_modify_alternate_brand(init_seg, GF_4CC('d','a','s','h'), 1);
}
- gf_isom_set_brand_info(init_seg, GF_4CC('i','s','o','5'), 1);
- gf_isom_modify_alternate_brand(init_seg, GF_4CC('d','a','s','h'), 1);
- if (i) gf_isom_close(in);
+ gf_isom_close(in);
}
if (e) {
GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Couldn't create initialization segment: error %s\n", gf_error_to_string(e) ));
@@ -1757,10 +1814,11 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32
*disable_bs_switching = 1;
gf_isom_delete(init_seg);
gf_delete_file(szInitName);
+ return GF_OK;
} else {
- gf_isom_close(init_seg);
+ e = gf_isom_close(init_seg);
}
- return GF_OK;
+ return e;
}
static GF_Err dasher_isom_segment_file(GF_DashSegInput *dash_input, const char *szOutName, GF_DASHSegmenterOptions *dash_cfg, Bool first_in_set)
@@ -1772,6 +1830,8 @@ static GF_Err dasher_isom_segment_file(GF_DashSegInput *dash_input, const char *
}
#endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/
+#ifndef GPAC_DISABLE_MPEG2TS
+
static GF_Err dasher_generic_classify_input(GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 input_idx, u32 *current_group_id, u32 *max_sap_type)
{
#ifdef GPAC_DISABLE_MEDIA_IMPORT
@@ -1797,6 +1857,9 @@ static GF_Err dasher_generic_classify_input(GF_DashSegInput *dash_inputs, u32 nb
if (strcmp(dash_inputs[input_idx].szMime, dash_inputs[i].szMime))
continue;
+ if (strcmp(dash_inputs[input_idx].role, dash_inputs[i].role))
+ continue;
+
memset(&probe, 0, sizeof(GF_MediaImporter));
probe.flags = GF_IMPORT_PROBE_ONLY;
probe.in_name = (char *)dash_inputs[i].file_name;
@@ -1863,6 +1926,10 @@ static GF_Err dasher_generic_classify_input(GF_DashSegInput *dash_inputs, u32 nb
return GF_OK;
}
+#endif
+
+#ifndef GPAC_DISABLE_MPEG2TS
+
static GF_Err dasher_generic_get_components_info(GF_DashSegInput *input, GF_DASHSegmenterOptions *opts)
{
#ifdef GPAC_DISABLE_MEDIA_IMPORT
@@ -1894,6 +1961,8 @@ static GF_Err dasher_generic_get_components_info(GF_DashSegInput *input, GF_DASH
#endif
return GF_OK;
}
+#endif
+
#ifndef GPAC_DISABLE_MPEG2TS
@@ -2445,6 +2514,8 @@ static GF_Err dasher_mp2t_get_components_info(GF_DashSegInput *dash_input, GF_DA
return GF_OK;
}
+#define NB_TSPCK_IO_BYTES 18800
+
static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *szOutName, GF_DASHSegmenterOptions *dash_cfg, Bool first_in_set)
{
GF_TSSegmenter ts_seg;
@@ -2457,8 +2528,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
const char *opt;
u32 i, startNumberRewind;
GF_Err e;
- u64 start, pcr_shift, next_pcr_shift, next_dts;
- Bool store_params=0;
+ u64 start, pcr_shift, next_pcr_shift;
Double cumulated_duration = 0;
u32 bandwidth = 0;
u32 segment_index;
@@ -2475,17 +2545,23 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
ts_seg.bandwidth = (u32) (ts_seg.file_size * 8 / dash_input->duration);
/*create bitstreams*/
- gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, 1, IdxName, basename, dash_input->representationID, dash_cfg->seg_rad_name, "six", 0, 0, 0);
segment_index = 1;
startNumberRewind = 0;
-
ts_seg.index_file = NULL;
ts_seg.index_bs = NULL;
if (!dash_cfg->dash_ctx && (dash_cfg->use_url_template != 2)) {
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
GF_SegmentTypeBox *styp;
+
+ gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, 1, IdxName, szOutName, dash_input->representationID, dash_cfg->seg_rad_name, "six", 0, 0, 0);
+
ts_seg.index_file = gf_f64_open(IdxName, "wb");
+ if (!ts_seg.index_file) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: Cannot create index file %s\n", IdxName));
+ e = GF_IO_ERR;
+ goto exit;
+ }
ts_seg.index_bs = gf_bs_from_file(ts_seg.index_file, GF_BITSTREAM_WRITE);
styp = (GF_SegmentTypeBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_STYP);
@@ -2500,6 +2576,8 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
#endif
}
+ gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, 1, IdxName, basename, dash_input->representationID, dash_cfg->seg_rad_name, "six", 0, 0, 0);
+
ts_seg.PCR_DTS_initial_diff = (u64) -1;
ts_seg.subduration = (u32) (dash_cfg->subduration * 90000);
@@ -2515,10 +2593,11 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
sscanf(opt, LLU, &offset);
while (!feof(ts_seg.src) && !ts_seg.has_seen_pat) {
- char data[188];
- u32 size = fread(data, 1, 188, ts_seg.src);
- if (size<188) break;
+ char data[NB_TSPCK_IO_BYTES];
+ u32 size = fread(data, 1, NB_TSPCK_IO_BYTES, ts_seg.src);
gf_m2ts_process_data(ts_seg.ts, data, size);
+
+ if (sizedash_ctx, szSectionName, "Setup", "yes");
gf_cfg_set_key(dash_cfg->dash_ctx, szSectionName, "ID", dash_input->representationID);
- store_params = 1;
} else {
if (!bandwidth) {
opt = gf_cfg_get_key(dash_cfg->dash_ctx, szSectionName, "Bandwidth");
@@ -2601,7 +2678,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_INITIALIZATION_TEMPLATE, 1, IdxName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "six", 0, bandwidth, segment_index);
fprintf(dash_cfg->mpd, " index=\"%s\"", IdxName);
}
- fprintf(dash_cfg->mpd, "/>\n", (u32) (90000*dash_cfg->segment_duration), segment_index, SegName);
+ fprintf(dash_cfg->mpd, "/>\n");
}
@@ -2618,9 +2695,6 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
if (dash_input->components[i].sample_rate)
fprintf(dash_cfg->mpd, " audioSamplingRate=\"%d\"", dash_input->components[i].sample_rate);
-
- if (dash_input->components[i].szLang[0])
- fprintf(dash_cfg->mpd, " lang=\"%s\"", dash_input->components[i].szLang);
}
if (strlen(szCodecs))
fprintf(dash_cfg->mpd, " codecs=\"%s\"", szCodecs);
@@ -2631,14 +2705,14 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
if (dash_cfg->single_file_mode==1) {
gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index);
- fprintf(dash_cfg->mpd, " %s\n", dash_cfg->seg_rad_name ? SegName : dash_input->file_name);
+ fprintf(dash_cfg->mpd, " %s\n", SegName);
fprintf(dash_cfg->mpd, " \n");
fprintf(dash_cfg->mpd, " \n", IdxName);
fprintf(dash_cfg->mpd, " \n");
/*we rewrite the file*/
- if (dash_cfg->seg_rad_name) rewrite_input = 1;
+ rewrite_input = 1;
} else {
if (dash_cfg->seg_rad_name && dash_cfg->use_url_template) {
if (dash_cfg->variable_seg_rad_name) {
@@ -2650,18 +2724,19 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
}
if (dash_cfg->time_shift_depth>=0)
- fprintf(dash_cfg->mpd, " presentationTimeOffset=\"%d\"", ts_seg.sidx->earliest_presentation_time + pcr_shift);
+ fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", ts_seg.sidx->earliest_presentation_time + pcr_shift);
fprintf(dash_cfg->mpd, "/>\n");
} else if (dash_cfg->time_shift_depth>=0) {
- fprintf(dash_cfg->mpd, " \n", ts_seg.sidx->earliest_presentation_time + pcr_shift);
+ fprintf(dash_cfg->mpd, " \n", ts_seg.sidx->earliest_presentation_time + pcr_shift);
GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH]: PTSOffset "LLD" - startNumber %d - time %g\n", ts_seg.sidx->earliest_presentation_time + pcr_shift, segment_index, (Double) (s64) (ts_seg.sidx->earliest_presentation_time + pcr_shift) / 90000.0));
}
} else {
gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index);
- fprintf(dash_cfg->mpd, " %s\n", dash_cfg->seg_rad_name ? SegName : dash_input->file_name);
+ if (dash_cfg->single_file_mode)
+ fprintf(dash_cfg->mpd, " %s\n",SegName);
fprintf(dash_cfg->mpd, " segment_duration));
if (dash_cfg->time_shift_depth>=0)
- fprintf(dash_cfg->mpd, " presentationTimeOffset=\"%d\"", ts_seg.sidx->earliest_presentation_time + pcr_shift);
+ fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", ts_seg.sidx->earliest_presentation_time + pcr_shift);
fprintf(dash_cfg->mpd, ">\n");
if (!dash_cfg->dash_ctx) {
@@ -2670,7 +2745,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
}
/*rewrite previous SegmentList entries*/
- if ((dash_cfg->single_file_mode==2) || (!dash_cfg->single_file_mode && !dash_cfg->use_url_template)) {
+ if ( dash_cfg->dash_ctx && ((dash_cfg->single_file_mode==2) || (!dash_cfg->single_file_mode && !dash_cfg->use_url_template))) {
/*rewrite previous URLs*/
const char *opt;
u32 count, i;
@@ -2690,7 +2765,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
fprintf(dash_cfg->mpd, " \n", start, start+ref->reference_size-1);
start += ref->reference_size;
}
- if (dash_cfg->seg_rad_name) rewrite_input = 1;
+ rewrite_input = 1;
} else {
FILE *src, *dst;
@@ -2699,15 +2774,21 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
src = gf_f64_open(dash_input->file_name, "rb");
start = ts_seg.sidx->first_offset;
for (i=0; inb_refs; i++) {
- char buf[4096];
+ char buf[NB_TSPCK_IO_BYTES];
GF_SIDXReference *ref = &ts_seg.sidx->refs[i];
- gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, basename, dash_input->representationID, dash_cfg->seg_rad_name, "ts", 0, bandwidth, segment_index);
+ gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, szOutName, dash_input->representationID, dash_cfg->seg_rad_name, "ts", 0, bandwidth, segment_index);
/*warning - we may introduce repeated sequence number when concatenating files. We should use switching
segments to force reset of the continuity counter for all our pids - we don't because most players don't car ...*/
if (dash_cfg->use_url_template != 2) {
dst = gf_f64_open(SegName, "wb");
+ if (!dst) {
+ fclose(src);
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: Cannot create segment file %s\n", SegName));
+ e = GF_IO_ERR;
+ goto exit;
+ }
gf_dasher_store_segment_info(dash_cfg, SegName, current_time);
dur = ref->subsegment_duration;
@@ -2719,8 +2800,8 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
end = start+ref->reference_size;
while (pos= end) {
+ u32 to_read = NB_TSPCK_IO_BYTES;
+ if (pos+NB_TSPCK_IO_BYTES >= end) {
to_read = (u32) (end-pos);
}
res = fread(buf, 1, to_read, src);
@@ -2737,9 +2818,9 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
fclose(dst);
}
start += ref->reference_size;
- segment_index++;
if (!dash_cfg->use_url_template) {
+ gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, basename, dash_input->representationID, dash_cfg->seg_rad_name, "ts", 0, bandwidth, segment_index);
fprintf(dash_cfg->mpd, " \n", SegName);
if (dash_cfg->dash_ctx) {
@@ -2750,6 +2831,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
}
}
+ segment_index++;
gf_set_progress("Extracting segment ", i+1, ts_seg.sidx->nb_refs);
}
fclose(src);
@@ -2762,15 +2844,28 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *
if (rewrite_input) {
FILE *in, *out;
- char buf[3760];
+ u64 fsize, done;
+ char buf[NB_TSPCK_IO_BYTES];
- in = gf_f64_open(dash_input->file_name, "rb");
+ gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, dash_cfg->seg_rad_name ? basename : szOutName, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index);
out = gf_f64_open(SegName, "wb");
+ if (!out) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: Cannot create segment file %s\n", SegName));
+ e = GF_IO_ERR;
+ goto exit;
+ }
+ in = gf_f64_open(dash_input->file_name, "rb");
+ gf_f64_seek(in, 0, SEEK_END);
+ fsize = gf_f64_tell(in);
+ gf_f64_seek(in, 0, SEEK_SET);
+ done = 0;
while (1) {
- u32 read = fread(buf, 1, 3760, in);
- if (!read) break;
+ u32 read = fread(buf, 1, NB_TSPCK_IO_BYTES, in);
gf_m2ts_restamp(buf, read, pcr_shift, is_pes);
fwrite(buf, 1, read, out);
+ done+=read;
+ gf_set_progress("Extracting segment ", done/188, fsize/188);
+ if (readtm_year, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+ fprintf(mpd, " availabilityStartTime=\"%d-%02d-%02dT%02d:%02d:%02dZ\"", 1900+t->tm_year, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
#endif
if ((s32)time_shift_depth>=0) {
@@ -3000,8 +3095,6 @@ static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool us
if (first_rep) {
u32 i;
- char langCode[4];
- langCode[3] = 0;
if (bitstream_switching_mode) {
for (i=0; inb_components; i++) {
@@ -3011,6 +3104,18 @@ static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool us
}
}
}
+
+ /*set role*/
+ if (strlen(first_rep->role)) {
+ if (!strcmp(first_rep->role, "caption") || !strcmp(first_rep->role, "subtitle") || !strcmp(first_rep->role, "main")
+ || !strcmp(first_rep->role, "alternate") || !strcmp(first_rep->role, "supplementary") || !strcmp(first_rep->role, "commentary")
+ || !strcmp(first_rep->role, "dub")
+ ) {
+ fprintf(mpd, " \n", first_rep->role);
+ }
+ }
+
+
if (first_rep->nb_components>1) {
for (i=0; inb_components; i++) {
struct _dash_component *comp = &first_rep->components[i];
@@ -3034,7 +3139,7 @@ static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool us
}
/*if lang not specified at adaptationSet level, put it here*/
if ((!szLang || !szLang[0]) && comp->szLang[0]) {
- fprintf(mpd, " lang=\"%s\"", langCode);
+ fprintf(mpd, " lang=\"%s\"", comp->szLang);
}
fprintf(mpd, "/>\n");
}
@@ -3049,7 +3154,7 @@ static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool us
return GF_OK;
}
-static GF_Err gf_dasher_init_context(GF_Config *dash_ctx, Bool *dynamic, u32 *timeShiftBufferDepth, const char *periodID)
+static GF_Err gf_dasher_init_context(GF_Config *dash_ctx, u32 *dynamic, u32 *timeShiftBufferDepth, const char *periodID)
{
const char *opt;
char szVal[100];
@@ -3066,11 +3171,13 @@ static GF_Err gf_dasher_init_context(GF_Config *dash_ctx, Bool *dynamic, u32 *ti
if (!opt) {
first_run = 1;
sprintf(szVal, "%d", *timeShiftBufferDepth);
- gf_cfg_set_key(dash_ctx, "DASH", "SessionType", *dynamic ? "dynamic" : "static");
+ gf_cfg_set_key(dash_ctx, "DASH", "SessionType", (*dynamic==2) ? "dynamic-debug" : ( *dynamic ? "dynamic" : "static" ) );
gf_cfg_set_key(dash_ctx, "DASH", "TimeShiftBufferDepth", szVal);
gf_cfg_set_key(dash_ctx, "DASH", "StoreParams", "yes");
} else {
- *dynamic = !strcmp(opt, "dynamic") ? 1 : 0;
+ *dynamic = 0;
+ if (!strcmp(opt, "dynamic")) *dynamic = 1;
+ else if (!strcmp(opt, "dynamic-debug")) *dynamic = 2;
opt = gf_cfg_get_key(dash_ctx, "DASH", "TimeShiftBufferDepth");
*timeShiftBufferDepth = atoi(opt);
gf_cfg_set_key(dash_ctx, "DASH", "StoreParams", "no");
@@ -3158,7 +3265,7 @@ u32 gf_dasher_next_update_time(GF_Config *dash_ctx, u32 mpd_update_time)
}
/*peform all file cleanup*/
-static Bool gf_dasher_cleanup(GF_Config *dash_ctx, Bool dash_dynamic, u32 mpd_update_time, u32 time_shift_depth, Double dash_duration)
+static Bool gf_dasher_cleanup(GF_Config *dash_ctx, u32 dash_dynamic, u32 mpd_update_time, u32 time_shift_depth, Double dash_duration)
{
Double max_dur = 0;
Double ellapsed = 0;
@@ -3187,18 +3294,22 @@ static Bool gf_dasher_cleanup(GF_Config *dash_ctx, Bool dash_dynamic, u32 mpd_up
if (!max_dur) return 1;
gf_net_get_ntp(&ntp_sec, &frac);
- ellapsed = ntp_sec;
- ellapsed -= prev_sec;
- /*check if we need to generate */
- if (ellapsed < max_dur - safety_dur ) {
- GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Asked to regenerate segments before expiration of the current segment list, please wait %g seconds - ignoring\n", max_dur + prev_sec - ntp_sec ));
- return 0;
- }
- if (ellapsed > max_dur) {
- GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Generating segments and MPD %g seconds too late\n", ellapsed - (u32) max_dur));
+ if (dash_dynamic==2) {
+ ellapsed = (u32)-1;
} else {
- /*generate as if max_dur has been reached*/
- ellapsed = max_dur;
+ ellapsed = ntp_sec;
+ ellapsed -= prev_sec;
+ /*check if we need to generate */
+ if (ellapsed < max_dur - safety_dur ) {
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Asked to regenerate segments before expiration of the current segment list, please wait %g seconds - ignoring\n", max_dur + prev_sec - ntp_sec ));
+ return 0;
+ }
+ if (ellapsed > max_dur) {
+ GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Generating segments and MPD %g seconds too late\n", ellapsed - (u32) max_dur));
+ } else {
+ /*generate as if max_dur has been reached*/
+ ellapsed = max_dur;
+ }
}
/*cleanup old segments*/
@@ -3252,10 +3363,10 @@ GF_EXPORT
GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *inputs, u32 nb_dash_inputs, GF_DashProfile dash_profile,
const char *mpd_title, const char *mpd_source, const char *mpd_copyright,
const char *mpd_moreInfoURL, const char **mpd_base_urls, u32 nb_mpd_base_urls,
- Bool use_url_template, Bool single_segment, Bool single_file, Bool bitstream_switching_mode,
+ Bool use_url_template, Bool single_segment, Bool single_file, GF_DashSwitchingMode bitstream_switching,
Bool seg_at_rap, Double dash_duration, char *seg_name, char *seg_ext,
Double frag_duration, s32 subsegs_per_sidx, Bool daisy_chain_sidx, Bool frag_at_rap, const char *tmpdir,
- GF_Config *dash_ctx, Bool dash_dynamic, u32 mpd_update_time, u32 time_shift_depth, Double subduration)
+ GF_Config *dash_ctx, u32 dash_dynamic, u32 mpd_update_time, u32 time_shift_depth, Double subduration)
{
u32 i, j, segment_mode;
char *sep, szSegName[GF_MAX_PATH], szSolvedSegName[GF_MAX_PATH], szTempMPD[GF_MAX_PATH];
@@ -3267,6 +3378,7 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input
u32 max_sap_type = 0;
Bool none_supported = 1;
Bool has_mpeg2 = 0;
+ Bool has_role = 0;
Double presentation_duration = 0;
GF_Err e = GF_OK;
FILE *mpd = NULL;
@@ -3284,7 +3396,6 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input
if (opt) {
Double seg_dur = atof(opt);
if (seg_dur != dash_duration) {
- gf_cfg_del(dash_ctx);
return GF_NOT_SUPPORTED;
}
} else {
@@ -3307,8 +3418,12 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input
dash_inputs[i].file_name = inputs[i].file_name;
strcpy(dash_inputs[i].representationID, inputs[i].representationID);
strcpy(dash_inputs[i].periodID, inputs[i].periodID);
+ strcpy(dash_inputs[i].role, inputs[i].role);
dash_inputs[i].bandwidth = inputs[i].bandwidth;
+ if (strlen(inputs[i].role) && strcmp(inputs[i].role, "main"))
+ has_role = 1;
+
if (!strlen(dash_inputs[i].periodID)) {
max_period = 1;
dash_inputs[i].period = 1;
@@ -3322,6 +3437,14 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input
}
memset(&dash_opts, 0, sizeof(GF_DASHSegmenterOptions));
+ /*set all default roles to main if needed*/
+ if (has_role) {
+ for (i=0; i=3) {
if (dash_profile) {
@@ -3390,7 +3512,6 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input
}
}
-
/*adjust params based on profiles*/
switch (dash_profile) {
case GF_DASH_PROFILE_LIVE:
@@ -3402,7 +3523,7 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input
seg_at_rap = 1;
single_segment = 1;
/*BS switching is meaningless in onDemand profile*/
- bitstream_switching_mode = 0;
+ bitstream_switching = GF_DASH_BSMODE_NONE;
use_url_template = single_file = 0;
break;
case GF_DASH_PROFILE_MAIN:
@@ -3437,7 +3558,6 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input
GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Spliting segments %sat GOP boundaries\n", frag_at_rap ? "and fragments " : ""));
}
-
dash_opts.mpd_name = mpdfile;
dash_opts.segments_start_with_rap = seg_at_rap;
dash_opts.segment_duration = dash_duration;
@@ -3452,6 +3572,7 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input
dash_opts.dash_ctx = dash_ctx;
dash_opts.time_shift_depth = (s32) time_shift_depth;
dash_opts.subduration = subduration;
+ dash_opts.inband_param_set = ((bitstream_switching == GF_DASH_BSMODE_INBAND) || (bitstream_switching == GF_DASH_BSMODE_SINGLE) ) ? 1 : 0;
for (cur_period=0; cur_periodisom, track->track_num, 1);
diff --git a/src/media_tools/isom_hinter.c b/src/media_tools/isom_hinter.c
index 05ebaee..253a53a 100644
--- a/src/media_tools/isom_hinter.c
+++ b/src/media_tools/isom_hinter.c
@@ -444,16 +444,20 @@ GF_RTPHinter *gf_hinter_track_new(GF_ISOFile *file, u32 TrackNum,
break;
case GF_ISOM_SUBTYPE_AVC_H264:
case GF_ISOM_SUBTYPE_AVC2_H264:
+ case GF_ISOM_SUBTYPE_AVC3_H264:
+ case GF_ISOM_SUBTYPE_AVC4_H264:
case GF_ISOM_SUBTYPE_SVC_H264:
{
GF_AVCConfig *avcc = gf_isom_avc_config_get(file, TrackNum, 1);
+ GF_AVCConfig *svcc = gf_isom_svc_config_get(file, TrackNum, 1);
required_rate = 90000; /* "90 kHz clock rate MUST be used"*/
hintType = GF_RTP_PAYT_H264_AVC;
streamType = GF_STREAM_VISUAL;
- avc_nalu_size = avcc->nal_unit_size;
+ avc_nalu_size = avcc ? avcc->nal_unit_size : svcc->nal_unit_size;
oti = GPAC_OTI_VIDEO_AVC;
PL_ID = 0x0F;
gf_odf_avc_cfg_del(avcc);
+ gf_odf_avc_cfg_del(svcc);
}
break;
case GF_ISOM_SUBTYPE_3GP_QCELP:
@@ -755,7 +759,51 @@ GF_Err gf_hinter_track_process(GF_RTPHinter *tkHint)
return GF_OK;
}
+static u32 write_nalu_config_array(char *sdpLine, GF_List *nalus)
+{
+ u32 i, count, b64s;
+ char b64[200];
+
+ count = gf_list_count(nalus);
+ for (i=0; idata, sl->size, b64, 200);
+ b64[b64s]=0;
+ strcat(sdpLine, b64);
+ if (i+1sequenceParameterSets) + gf_list_count(avcc->pictureParameterSets) + gf_list_count(avcc->sequenceParameterSetExtensions);
+ if (svcc) count += gf_list_count(svcc->sequenceParameterSets) + gf_list_count(svcc->pictureParameterSets);
+ if (!count) return;
+
+ strcat(sdpLine, "; sprop-parameter-sets=");
+
+ if (avcc) {
+ count = write_nalu_config_array(sdpLine, avcc->sequenceParameterSets);
+ if (count) strcat(sdpLine, ",");
+ count = write_nalu_config_array(sdpLine, avcc->sequenceParameterSetExtensions);
+ if (count) strcat(sdpLine, ",");
+ count = write_nalu_config_array(sdpLine, avcc->pictureParameterSets);
+ if (count) strcat(sdpLine, ",");
+ }
+
+ if (svcc) {
+ count = write_nalu_config_array(sdpLine, svcc->sequenceParameterSets);
+ if (count) strcat(sdpLine, ",");
+ count = write_nalu_config_array(sdpLine, svcc->pictureParameterSets);
+ if (count) strcat(sdpLine, ",");
+ }
+ count = strlen(sdpLine);
+ if (sdpLine[count-1] == ',')
+ sdpLine[count-1] = 0;
+}
GF_EXPORT
GF_Err gf_hinter_track_finalize(GF_RTPHinter *tkHint, Bool AddSystemInfo)
@@ -817,31 +865,20 @@ GF_Err gf_hinter_track_finalize(GF_RTPHinter *tkHint, Bool AddSystemInfo)
/*H264/AVC*/
else if (tkHint->rtp_p->rtp_payt == GF_RTP_PAYT_H264_AVC) {
GF_AVCConfig *avcc = gf_isom_avc_config_get(tkHint->file, tkHint->TrackNum, 1);
- sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", tkHint->rtp_p->PayloadType, avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication);
- if (gf_list_count(avcc->pictureParameterSets) || gf_list_count(avcc->sequenceParameterSets)) {
- u32 i, count, b64s;
- char b64[200];
- strcat(sdpLine, "; sprop-parameter-sets=");
- count = gf_list_count(avcc->sequenceParameterSets);
- for (i=0; isequenceParameterSets, i);
- b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
- b64[b64s]=0;
- strcat(sdpLine, b64);
- if (i+1pictureParameterSets);
- for (i=0; ipictureParameterSets, i);
- b64s = gf_base64_encode(sl->data, sl->size, b64, 200);
- b64[b64s]=0;
- strcat(sdpLine, b64);
- if (i+1file, tkHint->TrackNum, 1);
+ /*TODO - check syntax for SVC (might be some extra signaling)*/
+
+ if (avcc) {
+ sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", tkHint->rtp_p->PayloadType, avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication);
+ } else {
+ sprintf(sdpLine, "a=fmtp:%d profile-level-id=%02X%02X%02X; packetization-mode=1", tkHint->rtp_p->PayloadType, svcc->AVCProfileIndication, svcc->profile_compatibility, svcc->AVCLevelIndication);
}
+
+ write_avc_config(sdpLine, avcc, svcc);
+
gf_isom_sdp_add_track_line(tkHint->file, tkHint->HintTrack, sdpLine);
gf_odf_avc_cfg_del(avcc);
+ gf_odf_avc_cfg_del(svcc);
}
/*MPEG-4 decoder config*/
else if (tkHint->rtp_p->rtp_payt==GF_RTP_PAYT_MPEG4) {
diff --git a/src/media_tools/isom_tools.c b/src/media_tools/isom_tools.c
index 1d98204..9f4c1bc 100644
--- a/src/media_tools/isom_tools.c
+++ b/src/media_tools/isom_tools.c
@@ -40,10 +40,14 @@ GF_Err gf_media_change_par(GF_ISOFile *file, u32 track, s32 ar_num, s32 ar_den)
if (e) return e;
stype = gf_isom_get_media_subtype(file, track, 1);
- if ((stype==GF_ISOM_SUBTYPE_AVC_H264) || (stype==GF_ISOM_SUBTYPE_AVC2_H264) ) {
+ if ((stype==GF_ISOM_SUBTYPE_AVC_H264)
+ || (stype==GF_ISOM_SUBTYPE_AVC2_H264)
+ || (stype==GF_ISOM_SUBTYPE_AVC3_H264)
+ || (stype==GF_ISOM_SUBTYPE_AVC4_H264)
+ ) {
#ifndef GPAC_DISABLE_AV_PARSERS
GF_AVCConfig *avcc = gf_isom_avc_config_get(file, track, 1);
- AVC_ChangePAR(avcc, ar_num, ar_den);
+ gf_media_avc_change_par(avcc, ar_num, ar_den);
e = gf_isom_avc_config_update(file, track, 1, avcc);
gf_odf_avc_cfg_del(avcc);
if (e) return e;
@@ -543,6 +547,8 @@ GF_Err gf_media_make_3gpp(GF_ISOFile *mp4file)
break;
case GF_ISOM_SUBTYPE_AVC_H264:
case GF_ISOM_SUBTYPE_AVC2_H264:
+ case GF_ISOM_SUBTYPE_AVC3_H264:
+ case GF_ISOM_SUBTYPE_AVC4_H264:
case GF_ISOM_SUBTYPE_SVC_H264:
nb_vid++;
nb_avc++;
@@ -748,10 +754,14 @@ GF_ESD *gf_media_map_esd(GF_ISOFile *mp4, u32 track)
case GF_ISOM_SUBTYPE_MPEG4_CRYP:
case GF_ISOM_SUBTYPE_AVC_H264:
case GF_ISOM_SUBTYPE_AVC2_H264:
+ case GF_ISOM_SUBTYPE_AVC3_H264:
+ case GF_ISOM_SUBTYPE_AVC4_H264:
case GF_ISOM_SUBTYPE_SVC_H264:
case GF_ISOM_SUBTYPE_3GP_EVRC:
case GF_ISOM_SUBTYPE_3GP_QCELP:
case GF_ISOM_SUBTYPE_3GP_SMV:
+ case GF_ISOM_SUBTYPE_HVC1:
+ case GF_ISOM_SUBTYPE_HEV1:
return gf_isom_get_esd(mp4, track, 1);
}
@@ -884,21 +894,32 @@ static s32 gf_get_DQId(GF_ISOFile *file, u32 track)
{
GF_AVCConfig *svccfg;
GF_ISOSample *samp;
- u32 di = 0;
+ u32 di = 0, cur_extract_mode;
char *buffer;
GF_BitStream *bs;
u32 max_size = 4096;
u32 size, nalu_size_length;
u8 nal_type;
+ s32 DQId=0;
+ samp = NULL;
+ bs = NULL;
+ cur_extract_mode = gf_isom_get_nalu_extract_mode(file, track);
+ gf_isom_set_nalu_extract_mode(file, track, GF_ISOM_NALU_EXTRACT_INSPECT);
+ buffer = (char*)gf_malloc(sizeof(char) * max_size);
svccfg = gf_isom_svc_config_get(file, track, 1);
if (!svccfg)
- return 0;
+ {
+ DQId = 0;
+ goto exit;
+ }
samp = gf_isom_get_sample(file, track, 1, &di);
if (!samp)
- return -1;
+ {
+ DQId = -1;
+ goto exit;
+ }
bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
- buffer = (char*)gf_malloc(sizeof(char) * max_size);
nalu_size_length = 8 * svccfg->nal_unit_size;
while (gf_bs_available(bs))
{
@@ -910,10 +931,48 @@ static s32 gf_get_DQId(GF_ISOFile *file, u32 track)
gf_bs_read_data(bs, buffer, size);
nal_type = buffer[0] & 0x1F;
if (nal_type == GF_AVC_NALU_SVC_SLICE)
- return buffer[2] & 0x7F;
+ {
+ DQId = buffer[2] & 0x7F;
+ goto exit;
+ }
}
- return -1;
+exit:
+ if (svccfg) gf_odf_avc_cfg_del(svccfg);
+ if (samp) gf_isom_sample_del(&samp);
+ if (buffer) gf_free(buffer);
+ if (bs) gf_bs_del(bs);
+ gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode);
+ return DQId;;
}
+
+static Bool gf_isom_has_svc_explicit(GF_ISOFile *file, u32 track)
+{
+ GF_AVCConfig *svccfg;
+ GF_AVCConfigSlot *slc;
+ u32 i;
+ u8 type;
+ Bool ret = 0;
+
+ svccfg = gf_isom_svc_config_get(file, track, 1);
+ if (!svccfg)
+ return 0;
+
+ for (i = 0; i < gf_list_count(svccfg->sequenceParameterSets); i++)
+ {
+ slc = (GF_AVCConfigSlot *)gf_list_get(svccfg->sequenceParameterSets, i);
+ type = slc->data[0] & 0x1F;
+ if (type == GF_AVC_NALU_SEQ_PARAM)
+ {
+ ret = 1;
+ break;
+ }
+ }
+
+ if (svccfg) gf_odf_avc_cfg_del(svccfg);
+ return ret;
+}
+
+
static u32 gf_isom_get_track_id_max(GF_ISOFile *file)
{
u32 num_track, i, trackID;
@@ -934,87 +993,116 @@ static u32 gf_isom_get_track_id_max(GF_ISOFile *file)
GF_EXPORT
GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
{
- GF_AVCConfig *avccfg, *svccfg;
- u32 num_svc_track, num_sample, svc_track, dst_track, ref_trackID, ref_trackNum, max_id;
- u32 di, width, height, size, nalu_size_length;
- u32 i, j, t;
+ GF_AVCConfig *svccfg, *cfg;
+ u32 num_svc_track, num_sample, svc_track, dst_track, ref_trackID, ref_trackNum, max_id, di, width, height, size, nalu_size_length, i, j, t, max_size, num_pps, num_sps, num_subseq, NALUnitHeader, data_offset, data_length, count, timescale, cur_extract_mode;
GF_Err e;
- GF_AVCConfigSlot *slc;
+ GF_AVCConfigSlot *slc, *sl;
AVCState avc;
s32 sps_id, pps_id;
- GF_ISOSample *samp;
- GF_BitStream *bs;
+ GF_ISOSample *samp, *dst_samp;
+ GF_BitStream *bs, *dst_bs;
GF_BitStream ** sample_bs;
- u8 nal_type, nal_hdr;
- GF_ISOSample *dst_samp;
- GF_BitStream *dst_bs;
- char *buffer;
- //u8 dependency_id, quality_id, temporal_id, avc_dependency_id, avc_quality_id;
- u32 max_size = 4096;
+ u8 nal_type, nal_hdr, track_ref_index;
+ char *buffer;
s32 *sps_track, *sps, *pps;
- u32 num_pps, num_sps;
u64 offset;
Bool is_splited;
- Bool *first_sample_track;
+ Bool *first_sample_track, *is_subseq_pps;
u64 *first_DTS_track;
- u32 NALUnitHeader;
- u8 track_ref_index;
s8 sample_offset;
- u32 data_offset;
- u32 data_length;
- u32 count, timescale;
- avccfg = gf_isom_avc_config_get(file, track, 1);
+ max_size = 4096;
+ e = GF_OK;
+ samp = dst_samp = NULL;
+ bs = NULL;
+ sample_bs = NULL;
+ sps_track = sps = pps = NULL;
+ first_DTS_track = NULL;
+ first_sample_track = is_subseq_pps = NULL;
+ buffer = NULL;
+ cfg = NULL;
+ num_svc_track=0;
+ cur_extract_mode = gf_isom_get_nalu_extract_mode(file, track);
+ gf_isom_set_nalu_extract_mode(file, track, GF_ISOM_NALU_EXTRACT_INSPECT);
svccfg = gf_isom_svc_config_get(file, track, 1);
-
- is_splited = (avccfg) ? 0 : 1;
-
- /*if we have not any SVC -> stop*/
if (!svccfg)
- return GF_OK;
-
- timescale = gf_isom_get_media_timescale(file, track);
-
+ {
+ e = GF_OK;
+ goto exit;
+ }
num_sps = gf_list_count(svccfg->sequenceParameterSets);
+ if (!num_sps)
+ {
+ e = GF_OK;
+ goto exit;
+ }
num_pps = gf_list_count(svccfg->pictureParameterSets);
- /*we have a splited file with 1 SVC / track*/
- if (is_splited && num_pps == 1)
+ if ((gf_isom_get_avc_svc_type(file, track, 1) == GF_ISOM_AVCTYPE_SVC_ONLY) && !gf_isom_has_svc_explicit(file, track))
+ is_splited = 1;
+ else
+ is_splited = 0;
+ num_subseq = gf_isom_has_svc_explicit(file, track) ? num_sps - 1 : num_sps;
+
+ if (is_splited)
{
- /*use 'all' mode -> stop*/
- if (splitAll)
- return GF_OK;
- /*use 'base' mode -> merge SVC tracks*/
- else
- return gf_media_merge_svc(file, track, 0);
+ /*this track has only one SVC ...*/
+ if (num_sps == 1)
+ {
+ /*use 'all' mode -> stop*/
+ if (splitAll)
+ goto exit;
+ /*use 'base' mode -> merge SVC tracks*/
+ else
+ {
+ e = gf_media_merge_svc(file, track, 0);
+ goto exit;
+ }
+ }
+ /*this file has been in 'splitbase' mode*/
+ else if (!splitAll)
+ goto exit;
+
}
- num_svc_track = splitAll ? num_sps : 1;
+
+ timescale = gf_isom_get_media_timescale(file, track);
+ num_svc_track = splitAll ? num_subseq : 1;
max_id = gf_isom_get_track_id_max(file);
di = 0;
memset(&avc, 0, sizeof(AVCState));
avc.sps_active_idx = -1;
nalu_size_length = 8 * svccfg->nal_unit_size;
- /*read all sps*/
- sps = (s32 *) gf_malloc(num_sps * sizeof(s32));
- sps_track = (s32 *) gf_malloc(num_sps * sizeof(s32));
+ /*read all sps, but we need only the subset sequence parameter sets*/
+ sps = (s32 *) gf_malloc(num_subseq * sizeof(s32));
+ sps_track = (s32 *) gf_malloc(num_subseq * sizeof(s32));
+ count = 0;
for (i = 0; i < num_sps; i++)
{
- slc = gf_list_get(svccfg->sequenceParameterSets, i);
- sps_id = AVC_ReadSeqInfo(slc->data+1, slc->size-1, &avc,0, NULL);
+ slc = (GF_AVCConfigSlot *)gf_list_get(svccfg->sequenceParameterSets, i);
+ nal_type = slc->data[0] & 0x1F;
+ sps_id = gf_media_avc_read_sps(slc->data, slc->size, &avc, 0, NULL);
if (sps_id < 0) {
- return GF_NON_COMPLIANT_BITSTREAM;
+ e = GF_NON_COMPLIANT_BITSTREAM;
+ goto exit;
+ }
+ if (nal_type == GF_AVC_NALU_SVC_SUBSEQ_PARAM)
+ {
+ sps[count] = sps_id;
+ sps_track[count] = i;
+ count++;
}
- sps[i] = sps_id;
- sps_track[i] = i;
}
+ /*for testing*/
+ assert(count == num_subseq);
/*read all pps*/
pps = (s32 *) gf_malloc(num_pps * sizeof(s32));
for (j = 0; j < num_pps; j++)
{
- slc = gf_list_get(svccfg->pictureParameterSets, j);
- pps_id = AVC_ReadPictParamSet(slc->data+1, slc->size-1, &avc);
+ slc = (GF_AVCConfigSlot *)gf_list_get(svccfg->pictureParameterSets, j);
+ pps_id = gf_media_avc_read_pps(slc->data, slc->size, &avc);
if (pps_id < 0) {
- return GF_NON_COMPLIANT_BITSTREAM;
+ e = GF_NON_COMPLIANT_BITSTREAM;
+ goto exit;
}
pps[j] = pps_id;
}
@@ -1025,14 +1113,21 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
gf_isom_get_reference(file, track, GF_ISOM_REF_BASE, 1, &ref_trackNum);
ref_trackID = gf_isom_get_track_id(file, ref_trackNum);
}
+
+ buffer = (char*)gf_malloc(sizeof(char) * max_size);
/*read first sample for determinating the order of SVC tracks*/
count = 0;
samp = gf_isom_get_sample(file, track, 1, &di);
if (!samp)
- return GF_IO_ERR;
+ {
+ e = gf_isom_last_error(file);
+ goto exit;
+ }
bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
offset = 0;
- buffer = (char*)gf_malloc(sizeof(char) * max_size);
+ is_subseq_pps = (Bool *) gf_malloc(num_pps*sizeof(Bool));
+ for (i = 0; i < num_pps; i++)
+ is_subseq_pps[i] = 0;
while (gf_bs_available(bs))
{
size = gf_bs_read_int(bs, nalu_size_length);
@@ -1042,16 +1137,28 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
}
nal_hdr = gf_bs_read_u8(bs);
nal_type = nal_hdr & 0x1F;
- AVC_ParseNALU(bs, nal_hdr, &avc);
- gf_bs_seek(bs, offset+nalu_size_length/8);
+ gf_media_avc_parse_nalu(bs, nal_hdr, &avc);
+ e = gf_bs_seek(bs, offset+nalu_size_length/8);
+ if (e)
+ goto exit;
gf_bs_read_data(bs, buffer, size);
offset += size + nalu_size_length/8;
if (nal_type == GF_AVC_NALU_SVC_SLICE)
{
+ for (i = 0; i < num_pps; i++)
+ {
+ if (avc.s_info.pps->id == pps[i])
+ {
+ is_subseq_pps[i] = 1;
+ break;
+ }
+ }
+ if ((count > 0) && (avc.s_info.pps->sps_id == sps[count-1]))
+ continue;
/*verify the order of SPS, reorder if necessary*/
if (avc.s_info.pps->sps_id != sps[count])
{
- for (i = count+1; i < num_sps; i++)
+ for (i = count+1; i < num_subseq; i++)
{
/*swap two SPS*/
if (avc.s_info.pps->sps_id == sps[i])
@@ -1062,36 +1169,37 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
break;
}
}
- /*for testing: ensure that there are not two NALU which use the same SPS, so that we can use sps for separating layers*/
- assert(i < num_sps);
}
count++;
}
}
- /*for testing: ensure that the number of SPS is equal to the number of SVC layers*/
- assert(count == num_sps);
+ gf_bs_del(bs);
+ bs = NULL;
- gf_free(buffer);
- buffer = NULL;
+ gf_isom_sample_del(&samp);
+ samp = NULL;
for (t = 0; t < num_svc_track; t++)
{
- GF_AVCConfig *cfg;
-
e = GF_OK;
svc_track = gf_isom_new_track(file, t+1+max_id, GF_ISOM_MEDIA_VISUAL, timescale);
if (!svc_track)
{
e = gf_isom_last_error(file);
- return e;
+ goto exit;
}
gf_isom_set_track_enabled(file, svc_track, 1);
gf_isom_set_track_reference(file, svc_track, GF_ISOM_REF_BASE, ref_trackID);
cfg = gf_odf_avc_cfg_new();
cfg->complete_representation = 1; //SVC
+ /*this layer depends on the base layer and the lower layers*/
+ gf_isom_set_track_reference(file, svc_track, GF_ISOM_REF_SCAL, ref_trackID);
+ for (i = 0; i < t; i++)
+ gf_isom_set_track_reference(file, svc_track, GF_ISOM_REF_SCAL, i+1+max_id);
+
e = gf_isom_svc_config_new(file, svc_track, cfg, NULL, NULL, &di);
if (e)
- return e;
+ goto exit;
if (splitAll)
{
sps_id = sps[t];
@@ -1106,19 +1214,31 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
cfg->AVCLevelIndication = avc.sps[sps_id].level_idc;
cfg->AVCProfileIndication = avc.sps[sps_id].profile_idc;
cfg->nal_unit_size = svccfg->nal_unit_size;
- gf_list_add(cfg->sequenceParameterSets, gf_list_get(svccfg->sequenceParameterSets, sps_track[t]));
+ slc = (GF_AVCConfigSlot *)gf_list_get(svccfg->sequenceParameterSets, sps_track[t]);
+ sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ sl->id = slc->id;
+ sl->size = slc->size;
+ sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
+ memcpy(sl->data, slc->data, sizeof(char)*sl->size);
+ gf_list_add(cfg->sequenceParameterSets, sl);
for (j = 0; j < num_pps; j++)
{
pps_id = pps[j];
- if (avc.pps[pps_id].sps_id == sps_id)
+ if (is_subseq_pps[j] && (avc.pps[pps_id].sps_id == sps_id))
{
- gf_list_add(cfg->pictureParameterSets, gf_list_get(svccfg->pictureParameterSets, j));
+ slc = (GF_AVCConfigSlot *)gf_list_get(svccfg->pictureParameterSets, j);
+ sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ sl->id = slc->id;
+ sl->size = slc->size;
+ sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
+ memcpy(sl->data, slc->data, sizeof(char)*sl->size);
+ gf_list_add(cfg->pictureParameterSets, sl);
}
}
}
else
{
- for (i = 0; i < num_sps; i++)
+ for (i = 0; i < num_subseq; i++)
{
sps_id = sps[i];
width = avc.sps[sps_id].width;
@@ -1132,22 +1252,34 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
cfg->AVCLevelIndication = avc.sps[sps_id].level_idc;
cfg->AVCProfileIndication = avc.sps[sps_id].profile_idc;
cfg->nal_unit_size = svccfg->nal_unit_size;
- gf_list_add(cfg->sequenceParameterSets, gf_list_get(svccfg->sequenceParameterSets, sps_track[i]));
+ slc = (GF_AVCConfigSlot *)gf_list_get(svccfg->sequenceParameterSets, sps_track[i]);
+ sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ sl->id = slc->id;
+ sl->size = slc->size;
+ sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
+ memcpy(sl->data, slc->data, sizeof(char)*sl->size);
+ gf_list_add(cfg->sequenceParameterSets, sl);
for (j = 0; j < num_pps; j++)
{
- slc = gf_list_get(svccfg->pictureParameterSets, t);
- pps_id = AVC_ReadPictParamSet(slc->data+1, slc->size-1, &avc);
- if (pps_id < 0) {
- return GF_NON_COMPLIANT_BITSTREAM;
- }
+ pps_id = pps[j];
if (avc.pps[pps_id].sps_id == sps_id)
{
- gf_list_add(cfg->pictureParameterSets, gf_list_get(svccfg->pictureParameterSets, j));
+ slc = (GF_AVCConfigSlot *)gf_list_get(svccfg->pictureParameterSets, j);
+ sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ sl->id = slc->id;
+ sl->size = slc->size;
+ sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
+ memcpy(sl->data, slc->data, sizeof(char)*sl->size);
+ gf_list_add(cfg->pictureParameterSets, sl);
}
}
}
}
- gf_isom_svc_config_update(file, svc_track, 1, cfg, 0);
+ e = gf_isom_svc_config_update(file, svc_track, 1, cfg, 0);
+ if (e)
+ goto exit;
+ gf_odf_avc_cfg_del(cfg);
+ cfg = NULL;
}
num_sample = gf_isom_get_sample_count(file, track);
@@ -1157,28 +1289,69 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
first_DTS_track = (u64 *) gf_malloc((num_svc_track+1) * sizeof(u64));
for (t = 0; t <= num_svc_track; t++)
first_DTS_track[t] = 0;
-
for (i = 1; i <= num_sample; i++)
{
- u32 *prev_layer;
- u32 count_prev_layer;
-
- prev_layer = (u32 *) gf_malloc(num_svc_track * sizeof(u32));
- count_prev_layer = 0;
+ /*reset*/
+ memset(buffer, 0, max_size);
-
samp = gf_isom_get_sample(file, track, i, &di);
if (!samp)
- return GF_IO_ERR;
+ {
+ e = GF_IO_ERR;
+ goto exit;
+ }
/* Create (num_svc_track) SVC bitstreams + 1 AVC bitstream*/
sample_bs = (GF_BitStream **) gf_malloc(sizeof(GF_BitStream *) * (num_svc_track+1));
for (j = 0; j <= num_svc_track; j++)
sample_bs[j] = (GF_BitStream *) gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
+ /*write extractor*/
+ for (t = 0; t < num_svc_track; t++)
+ {
+ //reference to base layer
+ gf_bs_write_int(sample_bs[t+1], 14, nalu_size_length); // extractor 's size = 14
+ NALUnitHeader = 0; //reset
+ NALUnitHeader |= 0x1F000000; // NALU type = 31
+ gf_bs_write_u32(sample_bs[t+1], NALUnitHeader);
+ track_ref_index = (u8) gf_isom_has_track_reference(file, t+1+max_id, GF_ISOM_REF_SCAL, ref_trackID);
+ if (!track_ref_index)
+ {
+ e = GF_CORRUPTED_DATA;
+ goto exit;
+ }
+ gf_bs_write_u8(sample_bs[t+1], track_ref_index);
+ sample_offset = 0;
+ gf_bs_write_u8(sample_bs[t+1], sample_offset);
+ data_offset = 0;
+ gf_bs_write_u32(sample_bs[t+1], data_offset);
+ data_length = 0;
+ gf_bs_write_u32(sample_bs[t+1], data_length);
+ //reference to previous layer(s)
+ for (j = 0; j < t; j++)
+ {
+ gf_bs_write_int(sample_bs[t+1], 14, nalu_size_length);
+ NALUnitHeader = 0;
+ NALUnitHeader |= 0x1F000000;
+ gf_bs_write_u32(sample_bs[t+1], NALUnitHeader);
+ track_ref_index = (u8) gf_isom_has_track_reference(file, t+1+max_id, GF_ISOM_REF_SCAL, j+1+max_id);
+ if (!track_ref_index)
+ {
+ e = GF_CORRUPTED_DATA;
+ goto exit;
+ }
+ gf_bs_write_u8(sample_bs[t+1], track_ref_index);
+ sample_offset = 0;
+ gf_bs_write_u8(sample_bs[t+1], sample_offset);
+ data_offset = (j+1) * (nalu_size_length/8 + 14); // (nalu_size_length/8) bytes of NALU length field + 14 bytes of extractor per layer
+ gf_bs_write_u32(sample_bs[t+1], data_offset);
+ data_length = 0;
+ gf_bs_write_u32(sample_bs[t+1], data_length);
+ }
+ }
+
bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
offset = 0;
- buffer = (char*)gf_malloc(sizeof(char) * max_size);
while (gf_bs_available(bs))
{
size = gf_bs_read_int(bs, nalu_size_length);
@@ -1188,20 +1361,50 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
}
nal_hdr = gf_bs_read_u8(bs);
nal_type = nal_hdr & 0x1F;
- AVC_ParseNALU(bs, nal_hdr, &avc);
- gf_bs_seek(bs, offset+nalu_size_length/8);
+ gf_media_avc_parse_nalu(bs, nal_hdr, &avc);
+ e = gf_bs_seek(bs, offset+nalu_size_length/8);
+ if (e)
+ goto exit;
gf_bs_read_data(bs, buffer, size);
offset += size + nalu_size_length/8;
-
+
switch (nal_type) {
- //case GF_AVC_NALU_SVC_PREFIX_NALU:
- case GF_AVC_NALU_SVC_SLICE:
+ case GF_AVC_NALU_PIC_PARAM:
+ pps_id = gf_media_avc_read_pps(buffer, size, &avc);;
+ j = 0;
+ dst_track = 0;
+ while (j < num_pps)
+ {
+ if (pps_id == pps[j])
+ break;
+ j++;
+ }
+ if ((j < num_pps) && (is_subseq_pps[j]))
+ {
+ if (splitAll)
+ {
+ for (t = 0; t < num_svc_track; t++)
+ {
+ if (sps[t] == avc.pps[pps_id].sps_id)
+ {
+ dst_track = t + 1;
+ break;
+ }
+ }
+ }
+ else
+ dst_track = 1;
+ }
+ dst_bs = sample_bs[dst_track];
+ break;
+ case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
+ sps_id = gf_media_avc_read_sps(buffer, size, &avc, 0, NULL);
dst_track = 0;
if (splitAll)
{
- for (t = 0; t < num_svc_track; t++) // num_svc_track == num_pps
+ for (t = 0; t < num_svc_track; t++)
{
- if (sps_track[t] == (avc.s_info.pps)->sps_id)
+ if (sps[t] == sps_id)
{
dst_track = t + 1;
break;
@@ -1211,42 +1414,23 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
else
dst_track = 1;
dst_bs = sample_bs[dst_track];
- /*write extractor*/
- if (!gf_bs_get_position(dst_bs))
+ break;
+ case GF_AVC_NALU_SVC_SLICE:
+ dst_track = 0;
+ if (splitAll)
{
- //reference to base layer
- gf_bs_write_int(dst_bs, 14, nalu_size_length); // extractor 's size = 14
- NALUnitHeader = 0; //reset
- NALUnitHeader |= 0x1F000000; // NALU type = 31
- gf_bs_write_u32(dst_bs, NALUnitHeader);
- //track_ref_index is a trackID, not a trackNum. So when rewrite, gf_isom_get_track_id must be used to find trackNum
- track_ref_index = ref_trackID;
- gf_bs_write_u8(dst_bs, track_ref_index);
- sample_offset = 0;
- gf_bs_write_u8(dst_bs, sample_offset);
- data_offset = 0;
- gf_bs_write_u32(dst_bs, data_offset);
- data_length = 0;
- gf_bs_write_u32(dst_bs, data_length);
- //reference to previous layer(s)
- for (t = 0; t < count_prev_layer; t++)
+ for (t = 0; t < num_svc_track; t++)
{
- gf_bs_write_int(dst_bs, 14, nalu_size_length);
- NALUnitHeader = 0;
- NALUnitHeader |= 0x1F000000;
- gf_bs_write_u32(dst_bs, NALUnitHeader);
- track_ref_index = max_id + prev_layer[t];
- gf_bs_write_u8(dst_bs, track_ref_index);
- sample_offset = 0;
- gf_bs_write_u8(dst_bs, sample_offset);
- data_offset = (t+1) * (nalu_size_length/8 + 14); // (nalu_size_length/8) bytes of NALU length field + 14 bytes of extractor per layer
- gf_bs_write_u32(dst_bs, data_offset);
- data_length = 0;
- gf_bs_write_u32(dst_bs, data_length);
+ if (sps[t] == (avc.s_info.pps)->sps_id)
+ {
+ dst_track = t + 1;
+ break;
+ }
}
}
- prev_layer[count_prev_layer] = dst_track;
- count_prev_layer++;
+ else
+ dst_track = 1;
+ dst_bs = sample_bs[dst_track];
break;
default:
dst_bs = sample_bs[0];
@@ -1275,7 +1459,7 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
else
e = gf_isom_update_sample(file, track, i, dst_samp, 1);
if (e)
- return e;
+ goto exit;
gf_isom_sample_del(&dst_samp);
dst_samp = NULL;
}
@@ -1283,7 +1467,11 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
sample_bs[j] = NULL;
}
gf_free(sample_bs);
- gf_free(bs);
+ sample_bs = NULL;
+ gf_bs_del(bs);
+ bs = NULL;
+ gf_isom_sample_del(&samp);
+ samp = NULL;
}
/*add Editlist entry if DTS of the first sample is not zero*/
@@ -1302,84 +1490,131 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
}
}
- /*if this is a merged file: delete SVC config*/
+ /*if this is a merged file*/
if (!is_splited)
- gf_isom_svc_config_del(file, track, 1);
+ {
+ /*a normal stream: delete SVC config*/
+ if (!gf_isom_has_svc_explicit(file, track))
+ {
+ gf_isom_svc_config_del(file, track, 1);
+ }
+ else
+ {
+ s32 shift=0;
+
+ for (i = 0; i < gf_list_count(svccfg->sequenceParameterSets); i++)
+ {
+ slc = (GF_AVCConfigSlot *)gf_list_get(svccfg->sequenceParameterSets, i);
+ sps_id = gf_media_avc_read_sps(slc->data, slc->size, &avc, 0, NULL);
+ if (sps_id < 0) {
+ e = GF_NON_COMPLIANT_BITSTREAM;
+ goto exit;
+ }
+ nal_type = slc->data[0] & 0x1F;
+ if (nal_type == GF_AVC_NALU_SVC_SUBSEQ_PARAM)
+ {
+ gf_list_rem(svccfg->sequenceParameterSets, i);
+ gf_free(slc->data);
+ gf_free(slc);
+ i--;
+ }
+ }
+
+ for (j = 0; j < gf_list_count(svccfg->pictureParameterSets); j++)
+ {
+ slc = (GF_AVCConfigSlot *)gf_list_get(svccfg->pictureParameterSets, j);
+ pps_id = gf_media_avc_read_pps(slc->data, slc->size, &avc);
+ if (pps_id < 0) {
+ e = GF_NON_COMPLIANT_BITSTREAM;
+ goto exit;
+ }
+ if (is_subseq_pps[j+shift])
+ {
+ gf_list_rem(svccfg->pictureParameterSets, j);
+ gf_free(slc->data);
+ gf_free(slc);
+ j--;
+ }
+ }
+ e = gf_isom_svc_config_update(file, track, 1, svccfg, 0);
+ if (e)
+ goto exit;
+ }
+ }
/*if this is as splited file: delete this track*/
else
{
gf_isom_remove_track(file, track);
}
- return GF_OK;
+
+exit:
+ if (svccfg) gf_odf_avc_cfg_del(svccfg);
+ if (cfg) gf_odf_avc_cfg_del(cfg);
+ if (samp) gf_isom_sample_del(&samp);
+ if (dst_samp) gf_isom_sample_del(&dst_samp);
+ if (bs) gf_bs_del(bs);
+ if (sample_bs)
+ {
+ for (i = 0; i <= num_svc_track; i++)
+ gf_bs_del(sample_bs[i]);
+ gf_free(sample_bs);
+ }
+ if (sps_track) gf_free(sps_track);
+ if (sps) gf_free(sps);
+ if (pps) gf_free(pps);
+ if (first_sample_track) gf_free(first_sample_track);
+ if (first_DTS_track) gf_free(first_DTS_track);
+ if (buffer) gf_free(buffer);
+ if (is_subseq_pps) gf_free(is_subseq_pps);
+ gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode);
+ return e;
}
/* Merge SVC layers*/
GF_EXPORT
GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
{
- GF_AVCConfig *avccfg, *svccfg, *cfg;
- u32 merge_track;
- u32 num_track, num_sample;
+ GF_AVCConfig *svccfg, *cfg;
+ u32 merge_track, num_track, num_sample, size, i, t, di, max_size, nalu_size_length, ref_trackNum, ref_trackID, count, width, height, nb_EditList, media_ts, moov_ts;
GF_ISOSample *avc_samp, *samp, *dst_samp;
GF_BitStream *bs, *dst_bs;
GF_Err e;
- u32 size;
- u32 i, t;
- u32 di = 0;
char *buffer;
- u32 max_size = 4096;
- u32 nalu_size_length;
- u32 ref_trackNum, ref_trackID;
s32 *DQId;
- u32 count;
- u32 *list_track_sorted;
- u32 *cur_sample, *max_sample;
- u32 width = 0, height = 0;
+ u32 *list_track_sorted, *cur_sample, *max_sample;
u64 *DTS_offset;
- u32 nb_EditList;
- u32 media_ts, moov_ts;
u64 EditTime, SegmentDuration, MediaTime;
- u8 EditMode;
+ u8 EditMode, nal_type;
Bool first_sample;
- u64 first_DTS, offset, dur;
- u32 max_id;
- u32 timescale;
- u8 nal_type;
-
- avc_samp = samp = NULL;
-
- avccfg = gf_isom_avc_config_get(file, track, 1);
- if (!avccfg && mergeAll)
- return GF_BAD_PARAM;
- timescale = gf_isom_get_media_timescale(file, track);
+ u64 first_DTS, offset, dur;
+ GF_AVCConfigSlot *slc, *sl;
+
+ e = GF_OK;
+ di = 1;
+ max_size = 4096;
+ width = height = 0;
+ avc_samp = samp = dst_samp = NULL;
+ svccfg = cfg = NULL;
+ buffer = NULL;
+ bs = dst_bs = NULL;
+ DQId = NULL;
+ list_track_sorted = cur_sample = max_sample = NULL;
+ DTS_offset = NULL;
+
+ if (gf_isom_get_avc_svc_type(file, track, 1) == GF_ISOM_AVCTYPE_AVC_SVC)
+ goto exit;
num_track = gf_isom_get_track_count(file);
- if (num_track == 1) {
- if (avccfg) gf_odf_avc_cfg_del(avccfg);
- return GF_OK;
- }
-
- /*create a new merged track*/
- max_id = gf_isom_get_track_id_max(file);
- merge_track = gf_isom_new_track(file, max_id+1, GF_ISOM_MEDIA_VISUAL, timescale);
- gf_isom_set_track_enabled(file, merge_track, 1);
- /*add avc configuration if any*/
- if (avccfg)
- gf_isom_avc_config_new(file, merge_track, avccfg, NULL, NULL, &di);
-
- svccfg = gf_odf_avc_cfg_new();
- svccfg->complete_representation = 1;
- e = gf_isom_svc_config_new(file, merge_track, svccfg, NULL, NULL, &di);
- if (e) goto exit;
-
- if (avccfg) {
- ref_trackNum = track;
- ref_trackID = gf_isom_get_track_id(file, track);
- } else {
- gf_isom_get_reference(file, track, GF_ISOM_REF_BASE, 1, &ref_trackNum);
- ref_trackID = gf_isom_get_track_id(file, ref_trackNum);
+ if (num_track == 1)
+ goto exit;
+ gf_isom_get_reference(file, track, GF_ISOM_REF_BASE, 1, &ref_trackNum);
+ ref_trackID = gf_isom_get_track_id(file, ref_trackNum);
+ if (!ref_trackID)
+ {
+ e = GF_ISOM_INVALID_MEDIA;
+ goto exit;
}
-
+
list_track_sorted = (u32 *) gf_malloc(num_track * sizeof(u32));
DQId = (s32 *) gf_malloc(num_track * sizeof(s32));
count = 0;
@@ -1390,8 +1625,13 @@ GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
e = GF_ISOM_INVALID_MEDIA;
goto exit;
}
- if ((t != track) && !gf_isom_has_track_reference(file, t, GF_ISOM_REF_BASE, ref_trackID))
- continue;
+
+ if (!gf_isom_has_track_reference(file, t, GF_ISOM_REF_BASE, ref_trackID))
+ {
+ if (t != ref_trackNum) continue;
+ else if (!mergeAll) continue;
+ }
+
while ((pos < count ) && (DQId[pos] <= track_DQId))
pos++;
for (i = count; i > pos; i--)
@@ -1404,16 +1644,20 @@ GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
count++;
}
- if (mergeAll)
- {
- gf_isom_get_visual_info(file, list_track_sorted[0], 1, &width, &height);
- }
- else
+ merge_track = list_track_sorted[0];
+ gf_isom_set_track_enabled(file, merge_track, 1);
+ /*rewrite svccfg*/
+ svccfg = gf_odf_avc_cfg_new();
+ svccfg->complete_representation = 1;
+ e = gf_isom_svc_config_new(file, merge_track, svccfg, NULL, NULL, &di);
+ if (e) goto exit;
+ /*rewrite visual info*/
+ if (!mergeAll)
{
for (t = 0; t < count; t++)
gf_isom_get_visual_info(file, list_track_sorted[t], 1, &width, &height);
+ gf_isom_set_visual_info(file, merge_track, 1, width, height);
}
- gf_isom_set_visual_info(file, merge_track, 1, width, height);
for (t = 0; t < count; t++)
{
@@ -1430,18 +1674,30 @@ GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
svccfg->nal_unit_size = cfg->nal_unit_size;
for (i = 0; i < gf_list_count(cfg->sequenceParameterSets); i++)
{
- gf_list_add(svccfg->sequenceParameterSets, gf_list_get(cfg->sequenceParameterSets, i));
- }
+ slc = (GF_AVCConfigSlot *)gf_list_get(cfg->sequenceParameterSets, i);
+ sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ sl->id = slc->id;
+ sl->size = slc->size;
+ sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
+ memcpy(sl->data, slc->data, sizeof(char)*sl->size);
+ gf_list_add(svccfg->sequenceParameterSets, sl);
+ }
for (i = 0; i < gf_list_count(cfg->pictureParameterSets); i++)
{
- gf_list_add(svccfg->pictureParameterSets, gf_list_get(cfg->pictureParameterSets, i));
+ slc = (GF_AVCConfigSlot *)gf_list_get(cfg->pictureParameterSets, i);
+ sl = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ sl->id = slc->id;
+ sl->size = slc->size;
+ sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
+ memcpy(sl->data, slc->data, sizeof(char)*sl->size);
+ gf_list_add(svccfg->pictureParameterSets, sl);
}
if (mergeAll)
gf_isom_svc_config_update(file, merge_track, 1, svccfg, 1);
else
gf_isom_svc_config_update(file, merge_track, 1, svccfg, 0);
-
gf_odf_avc_cfg_del(cfg);
+ cfg = NULL;
}
cur_sample = (u32 *) gf_malloc(count * sizeof(u32));
@@ -1479,6 +1735,9 @@ GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
nalu_size_length = 8 * svccfg->nal_unit_size;
first_sample = 1;
first_DTS = 0;
+ buffer = (char*)gf_malloc(sizeof(char) * max_size);
+ for (t = 1; t <= num_track; t++)
+ gf_isom_set_nalu_extract_mode(file, t, GF_ISOM_NALU_EXTRACT_INSPECT);
for (i = 1; i <= num_sample; i++)
{
dst_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
@@ -1494,7 +1753,12 @@ GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
gf_bs_write_int(dst_bs, 14, nalu_size_length); // extractor 's size = 14
NALUnitHeader |= 0x1F000000; // NALU type = 31
gf_bs_write_u32(dst_bs, NALUnitHeader);
- track_ref_index = ref_trackID;
+ track_ref_index = (u8) gf_isom_has_track_reference(file, merge_track, GF_ISOM_REF_SCAL, ref_trackID);
+ if (!track_ref_index)
+ {
+ e = GF_CORRUPTED_DATA;
+ goto exit;
+ }
gf_bs_write_u8(dst_bs, track_ref_index);
sample_offset = 0;
gf_bs_write_u8(dst_bs, sample_offset);
@@ -1503,7 +1767,6 @@ GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
data_length = 0;
gf_bs_write_u32(dst_bs, data_length);
}
- buffer = (char*)gf_malloc(sizeof(char) * max_size);
avc_samp = gf_isom_get_sample(file, ref_trackNum, i, &di);
if (!avc_samp) {
@@ -1524,6 +1787,8 @@ GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
if ((samp->DTS + DTS_offset[t]) != avc_samp->DTS)
continue;
bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
+ /*reset*/
+ memset(buffer, 0, sizeof(char) * max_size);
while (gf_bs_available(bs))
{
size = gf_bs_read_int(bs, nalu_size_length);
@@ -1560,15 +1825,16 @@ GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
dst_samp->DTS = avc_samp->DTS - first_DTS;
dst_samp->IsRAP = avc_samp->IsRAP;
gf_bs_get_content(dst_bs, &dst_samp->data, &dst_samp->dataLength);
- e = gf_isom_add_sample(file, merge_track, 1, dst_samp);
- gf_bs_del(dst_bs);
- dst_bs = NULL;
- gf_isom_sample_del(&dst_samp);
+ e = gf_isom_update_sample(file, merge_track, i, dst_samp, 1);
if (e)
goto exit;
}
gf_isom_sample_del(&avc_samp);
avc_samp = NULL;
+ gf_bs_del(dst_bs);
+ dst_bs = NULL;
+ gf_isom_sample_del(&dst_samp);
+ dst_samp = NULL;
}
/*Add EditList if nessessary*/
@@ -1585,18 +1851,30 @@ GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
/*Delete SVC track(s) that references to ref_track*/
for (t = 1; t <= num_track; t++)
{
- if ((t != track) && !gf_isom_has_track_reference(file, t, GF_ISOM_REF_BASE, ref_trackID))
- continue;
- gf_isom_remove_track(file, t);
- num_track--; //we removed one track from file
- t--;
+ if (gf_isom_has_track_reference(file, t, GF_ISOM_REF_BASE, ref_trackID) && (t != merge_track))
+ {
+ gf_isom_remove_track(file, t);
+ num_track--; //we removed one track from file
+ t--;
+ }
}
exit:
if (avc_samp) gf_isom_sample_del(&avc_samp);
if (samp) gf_isom_sample_del(&samp);
- if (avccfg) gf_odf_avc_cfg_del(avccfg);
+ if (dst_samp) gf_isom_sample_del(&dst_samp);
if (svccfg) gf_odf_avc_cfg_del(svccfg);
+ if (cfg) gf_odf_avc_cfg_del(cfg);
+ if (bs) gf_bs_del(bs);
+ if (dst_bs) gf_bs_del(dst_bs);
+ if (buffer) gf_free(buffer);
+ if (DQId) gf_free(DQId);
+ if (list_track_sorted) gf_free(list_track_sorted);
+ if (cur_sample) gf_free(cur_sample);
+ if (max_sample) gf_free(max_sample);
+ if (DTS_offset) gf_free(DTS_offset);
+ for (t = 1; t <= gf_isom_get_track_count(file); t++)
+ gf_isom_set_nalu_extract_mode(file, t, GF_ISOM_NALU_EXTRACT_DEFAULT);
return e;
}
diff --git a/src/media_tools/m2ts_mux.c b/src/media_tools/m2ts_mux.c
index ed1f578..05bb8fc 100644
--- a/src/media_tools/m2ts_mux.c
+++ b/src/media_tools/m2ts_mux.c
@@ -1619,9 +1619,17 @@ GF_M2TS_Mux_Stream *gf_m2ts_program_stream_add(GF_M2TS_Mux_Program *program, str
break;
case GPAC_OTI_VIDEO_AVC:
stream->mpeg2_stream_type = GF_M2TS_VIDEO_H264;
- /*make sure we send AU delim NALU in same PES as first VCL NAL: 6 bytes (AU delim) + 4 byte start code + first nal header*/
+ /*make sure we send AU delim NALU in same PES as first VCL NAL: 6 bytes (start code + 1 nal hdr + AU delim)
+ + 4 byte start code + first nal header*/
stream->min_bytes_copy_from_next = 11;
break;
+ case GPAC_OTI_VIDEO_HEVC:
+ stream->mpeg2_stream_type = GF_M2TS_VIDEO_HEVC;
+ /*make sure we send AU delim NALU in same PES as first VCL NAL: 7 bytes (4 start code + 2 nal header + 1 AU delim)
+ + 4 byte start code + first nal header*/
+ stream->min_bytes_copy_from_next = 12;
+ break;
+
case GPAC_OTI_VIDEO_MPEG1:
stream->mpeg2_stream_type = GF_M2TS_VIDEO_MPEG1;
break;
@@ -1739,6 +1747,7 @@ GF_M2TS_Mux_Program *gf_m2ts_mux_program_add(GF_M2TS_Mux *muxer, u32 program_num
}
program->pmt = gf_m2ts_stream_new(pmt_pid);
program->pmt->program = program;
+ program->pmt->table_needs_update = 1;
muxer->pat->table_needs_update = 1;
program->pmt->process = gf_m2ts_stream_process_pmt;
program->pmt->refresh_rate_ms = pmt_refresh_rate ? pmt_refresh_rate : (u32) -1;
diff --git a/src/media_tools/m3u8.c b/src/media_tools/m3u8.c
index b8777bc..fdaad15 100644
--- a/src/media_tools/m3u8.c
+++ b/src/media_tools/m3u8.c
@@ -495,20 +495,30 @@ GF_Err parse_root_playlist(const char * file, VariantPlaylist ** playlist, const
GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const char * baseURL, Program * in_program, PlaylistElement *sub_playlist)
{
int len, i, currentLineNumber;
- FILE * f;
+ FILE * f=NULL;
+ char *m3u8_payload;
+ u32 m3u8_size, m3u8pos;
VariantPlaylist * pl;
char currentLine[M3U8_BUF_SIZE];
char ** attributes = NULL;
s_accumulated_attributes attribs;
- f = gf_f64_open(file, "rt");
- if (!f) {
- GF_LOG(GF_LOG_ERROR, GF_LOG_DASH,("[M3U8] Cannot Open m3u8 file %s for reading\n", file));
- return GF_SERVICE_ERROR;
+
+ if (!strncmp(file, "gmem://", 7)) {
+ if (sscanf(file, "gmem://%d@%p", &m3u8_size, &m3u8_payload) != 2) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH,("[M3U8] Cannot Open m3u8 source %s for reading\n", file));
+ return GF_SERVICE_ERROR;
+ }
+ } else {
+ f = gf_f64_open(file, "rt");
+ if (!f) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH,("[M3U8] Cannot Open m3u8 file %s for reading\n", file));
+ return GF_SERVICE_ERROR;
+ }
}
if (*playlist == NULL) {
*playlist = variant_playlist_new();
if (!(*playlist)) {
- fclose(f);
+ if (f) fclose(f);
return GF_OUT_OF_MEM;
}
}
@@ -522,8 +532,26 @@ GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const
attribs.isPlaylistEnded = 0;
attribs.minMediaSequence = 0;
attribs.currentMediaSequence = 0;
- while (fgets(currentLine, sizeof(currentLine), f)) {
+ m3u8pos=0;
+ while (1) {
char * eof;
+ if (f) {
+ if (!fgets(currentLine, sizeof(currentLine), f))
+ break;
+ } else {
+ u32 __idx=0;
+ if (m3u8pos>=m3u8_size)
+ break;
+ while (1) {
+ currentLine[__idx] = m3u8_payload[m3u8pos];
+ __idx++;
+ m3u8pos++;
+ if ((currentLine[__idx-1]=='\n') || (currentLine[__idx-1]=='\r')) {
+ currentLine[__idx]=0;
+ break;
+ }
+ }
+ }
currentLineNumber++;
eof = strchr(currentLine, '\r');
if (eof)
@@ -601,7 +629,7 @@ GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const
if (program == NULL) {
/* OUT of memory */
variant_playlist_del(*playlist);
- fclose(f);
+ if (f) fclose(f);
playlist = NULL;
return GF_OUT_OF_MEM;
}
@@ -643,7 +671,7 @@ GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const
/* OUT of memory */
variant_playlist_del(*playlist);
playlist = NULL;
- fclose(f);
+ if (f) fclose(f);
return GF_OUT_OF_MEM;
}
assert( fullURL);
@@ -671,7 +699,7 @@ GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const
/* OUT of memory */
variant_playlist_del(*playlist);
playlist = NULL;
- fclose(f);
+ if (f) fclose(f);
return GF_OUT_OF_MEM;
}
assert(currentPlayList->element.playlist.elements);
@@ -690,7 +718,7 @@ GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const
variant_playlist_del(*playlist);
playlist_element_del(currentPlayList);
playlist = NULL;
- fclose(f);
+ if (f) fclose(f);
return GF_OUT_OF_MEM;
}
gf_list_add(currentPlayList->element.playlist.elements, subElement);
@@ -717,7 +745,7 @@ GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const
variant_playlist_del(*playlist);
playlist_element_del(currentPlayList);
playlist = NULL;
- fclose(f);
+ if (f) fclose(f);
return GF_OUT_OF_MEM;
}
gf_list_add(currentPlayList->element.playlist.elements, subElement);
@@ -763,7 +791,7 @@ GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const
}
}
}
- fclose(f);
+ if (f) fclose(f);
for (i=0; i < (int) gf_list_count(pl->programs); i++) {
u32 j;
diff --git a/src/media_tools/media_export.c b/src/media_tools/media_export.c
index d112e28..ccb5283 100644
--- a/src/media_tools/media_export.c
+++ b/src/media_tools/media_export.c
@@ -42,8 +42,9 @@
#include
#endif
-
+#ifndef GPAC_DISABLE_ZLIB
#include
+#endif
GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc);
@@ -287,9 +288,13 @@ GF_Err gf_media_export_samples(GF_MediaExporter *dumper)
gf_export_message(dumper, GF_OK, "Dumping MPEG-4 Visual sample%s", szNum);
break;
case GPAC_OTI_VIDEO_AVC:
- strcpy(szEXT, ".h264");
+ strcpy(szEXT, ".264");
gf_export_message(dumper, GF_OK, "Dumping MPEG-4 AVC-H264 Visual sample%s", szNum);
break;
+ case GPAC_OTI_VIDEO_HEVC:
+ strcpy(szEXT, ".hvc");
+ gf_export_message(dumper, GF_OK, "Dumping MPEG-H HEVC Visual sample%s", szNum);
+ break;
case GPAC_OTI_IMAGE_JPEG:
strcpy(szEXT, ".jpg");
gf_export_message(dumper, GF_OK, "Dumping JPEG image%s", szNum);
@@ -374,9 +379,19 @@ GF_Err gf_media_export_samples(GF_MediaExporter *dumper)
} else if (m_stype==GF_ISOM_SUBTYPE_AC3) {
gf_export_message(dumper, GF_OK, "Extracting AC3 sample%s", szNum);
strcpy(szEXT, ".ac3");
- } else if ((m_stype==GF_ISOM_SUBTYPE_AVC_H264) || (m_stype==GF_ISOM_SUBTYPE_AVC2_H264) || (m_stype==GF_ISOM_SUBTYPE_SVC_H264) ) {
+ } else if ((m_stype==GF_ISOM_SUBTYPE_AVC_H264)
+ || (m_stype==GF_ISOM_SUBTYPE_AVC2_H264)
+ || (m_stype==GF_ISOM_SUBTYPE_AVC3_H264)
+ || (m_stype==GF_ISOM_SUBTYPE_AVC4_H264)
+ || (m_stype==GF_ISOM_SUBTYPE_SVC_H264)
+ ) {
strcpy(szEXT, ".h264");
gf_export_message(dumper, GF_OK, "Dumping MPEG-4 AVC-H264 Visual sample%s", szNum);
+ } else if ((m_stype==GF_ISOM_SUBTYPE_HVC1)
+ || (m_stype==GF_ISOM_SUBTYPE_HEV1)
+ ) {
+ strcpy(szEXT, ".hvc");
+ gf_export_message(dumper, GF_OK, "Dumping MPEG-H HEVC Visual sample%s", szNum);
} else if (m_type==GF_ISOM_MEDIA_FLASH) {
gf_export_message(dumper, GF_OK, "Extracting Macromedia Flash Movie sample%s", szNum);
strcpy(szEXT, ".swf");
@@ -617,7 +632,8 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper)
char szName[1000], szEXT[5], GUID[16];
FILE *out;
unsigned int *qcp_rates, rt_cnt; /*contains constants*/
- GF_AVCConfig *avccfg;
+ GF_AVCConfig *avccfg, *svccfg;
+ GF_HEVCConfig *hevccfg;
GF_M4ADecSpecInfo a_cfg;
GF_BitStream *bs;
u32 track, i, di, count, m_type, m_stype, dsi_size, qcp_type;
@@ -629,8 +645,10 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper)
dsi_size = 0;
dsi = NULL;
+ hevccfg = NULL;
avccfg = NULL;
-
+ svccfg = NULL;
+
if (!(track = gf_isom_get_track_by_id(dumper->file, dumper->trackID))) {
GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Wrong track ID %d for file %s \n", dumper->trackID, gf_isom_get_filename(dumper->file)));
return GF_BAD_PARAM;
@@ -667,10 +685,17 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper)
break;
case GPAC_OTI_VIDEO_AVC:
avccfg = gf_isom_avc_config_get(dumper->file, track, 1);
+ svccfg = gf_isom_svc_config_get(dumper->file, track, 1);
if (add_ext)
strcat(szName, ".h264");
gf_export_message(dumper, GF_OK, "Extracting MPEG-4 AVC-H264 stream to h264");
break;
+ case GPAC_OTI_VIDEO_HEVC:
+ hevccfg = gf_isom_hevc_config_get(dumper->file, track, 1);
+ if (add_ext)
+ strcat(szName, ".hvc");
+ gf_export_message(dumper, GF_OK, "Extracting MPEG-H HEVC stream to hevc");
+ break;
case GPAC_OTI_VIDEO_MPEG1:
if (add_ext)
strcat(szName, ".m1v");
@@ -827,11 +852,24 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper)
strcat(szName, ".263");
} else if (m_stype==GF_ISOM_SUBTYPE_3GP_DIMS) {
return gf_media_export_nhml(dumper, 1);
- } else if ((m_stype==GF_ISOM_SUBTYPE_AVC_H264) || (m_stype==GF_ISOM_SUBTYPE_AVC2_H264) || (m_stype==GF_ISOM_SUBTYPE_SVC_H264) ) {
+ } else if ((m_stype==GF_ISOM_SUBTYPE_AVC_H264)
+ || (m_stype==GF_ISOM_SUBTYPE_AVC2_H264)
+ || (m_stype==GF_ISOM_SUBTYPE_AVC3_H264)
+ || (m_stype==GF_ISOM_SUBTYPE_AVC4_H264)
+ || (m_stype==GF_ISOM_SUBTYPE_SVC_H264)
+ ) {
avccfg = gf_isom_avc_config_get(dumper->file, track, 1);
+ svccfg = gf_isom_svc_config_get(dumper->file, track, 1);
if (add_ext)
strcat(szName, ".h264");
gf_export_message(dumper, GF_OK, "Extracting MPEG-4 AVC-H264 stream to h264");
+ } else if ((m_stype==GF_ISOM_SUBTYPE_HEV1)
+ || (m_stype==GF_ISOM_SUBTYPE_HVC1)
+ ) {
+ hevccfg = gf_isom_hevc_config_get(dumper->file, track, 1);
+ if (add_ext)
+ strcat(szName, ".hvc");
+ gf_export_message(dumper, GF_OK, "Extracting MPEG-H HEVC stream to hevc");
} else if (m_type==GF_ISOM_MEDIA_FLASH) {
gf_export_message(dumper, GF_OK, "Extracting Macromedia Flash Movie");
if (add_ext)
@@ -863,8 +901,12 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper)
if (dumper->flags & GF_EXPORT_PROBE_ONLY) {
if (dsi) gf_free(dsi);
if (avccfg) gf_odf_avc_cfg_del(avccfg);
+ if (svccfg) gf_odf_avc_cfg_del(svccfg);
+ if (hevccfg) gf_odf_hevc_cfg_del(hevccfg);
return GF_OK;
}
+ if (dumper->flags & GF_EXPORT_SVC_LAYER)
+ gf_isom_set_nalu_extract_mode(dumper->file, track, GF_ISOM_NALU_EXTRACT_LAYER_ONLY);
if (is_ogg) return gf_dump_to_ogg(dumper, is_stdout ? NULL : szName, track);
@@ -897,6 +939,8 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper)
if (!out) {
if (dsi) gf_free(dsi);
if (avccfg) gf_odf_avc_cfg_del(avccfg);
+ if (svccfg) gf_odf_avc_cfg_del(svccfg);
+ if (hevccfg) gf_odf_hevc_cfg_del(hevccfg);
return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName);
}
bs = gf_bs_from_file(out, GF_BITSTREAM_WRITE);
@@ -925,6 +969,92 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper)
gf_bs_write_data(bs, sl->data, sl->size);
}
}
+ if (svccfg) {
+ if (!(dumper->flags & GF_EXPORT_SVC_LAYER))
+ {
+ GF_AVCConfig *cfg;
+ u32 ref_track = 0, t;
+ s32 countRef;
+
+ // copy avcC and svcC from base layer
+ gf_isom_get_reference(dumper->file, track, GF_ISOM_REF_BASE, 1, &ref_track);
+ cfg = gf_isom_avc_config_get(dumper->file, ref_track, 1);
+ if (cfg)
+ {
+ count = gf_list_count(cfg->sequenceParameterSets);
+ for (i =0; i < count; i++) {
+ GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(cfg->sequenceParameterSets, i);
+ gf_bs_write_u32(bs, 1);
+ gf_bs_write_data(bs, sl->data, sl->size);
+ }
+ count = gf_list_count(cfg->pictureParameterSets);
+ for (i = 0; i < count; i++) {
+ GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(cfg->pictureParameterSets, i);
+ gf_bs_write_u32(bs, 1);
+ gf_bs_write_data(bs, sl->data, sl->size);
+ }
+ gf_odf_avc_cfg_del(cfg);
+ cfg = NULL;
+ }
+
+ // copy avcC and svcC from lower layer
+ countRef = gf_isom_get_reference_count(dumper->file, track, GF_ISOM_REF_SCAL);
+ if (countRef < 0)
+ {
+ e = gf_isom_last_error(dumper->file);
+ goto exit;
+ }
+ for (t = 2; t <= (u32) countRef; t++) // referenceIndex 1 is the base layer
+ {
+ gf_isom_get_reference(dumper->file, track, GF_ISOM_REF_SCAL, t, &ref_track);
+ cfg = gf_isom_svc_config_get(dumper->file, ref_track, 1);
+ if (cfg)
+ {
+ count = gf_list_count(cfg->sequenceParameterSets);
+ for (i = 0; i < count; i++) {
+ GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(cfg->sequenceParameterSets, i);
+ gf_bs_write_u32(bs, 1);
+ gf_bs_write_data(bs, sl->data, sl->size);
+ }
+ count = gf_list_count(cfg->pictureParameterSets);
+ for (i = 0; i < count; i++) {
+ GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(cfg->pictureParameterSets, i);
+ gf_bs_write_u32(bs, 1);
+ gf_bs_write_data(bs, sl->data, sl->size);
+ }
+ gf_odf_avc_cfg_del(cfg);
+ cfg = NULL;
+ }
+ }
+ }
+
+ count = gf_list_count(svccfg->sequenceParameterSets);
+ for (i=0;isequenceParameterSets, i);
+ gf_bs_write_u32(bs, 1);
+ gf_bs_write_data(bs, sl->data, sl->size);
+ }
+ count = gf_list_count(svccfg->pictureParameterSets);
+ for (i=0;ipictureParameterSets, i);
+ gf_bs_write_u32(bs, 1);
+ gf_bs_write_data(bs, sl->data, sl->size);
+ }
+ }
+
+
+ if (hevccfg) {
+ count = gf_list_count(hevccfg->param_array);
+ for (i=0;iparam_array, i);
+ for (j=0; jnalus); j++) {
+ GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(ar->nalus, j);
+ gf_bs_write_u32(bs, 1);
+ gf_bs_write_data(bs, sl->data, sl->size);
+ }
+ }
+ }
qcp_rates = NULL;
count = gf_isom_get_sample_count(dumper->file, track);
@@ -1039,19 +1169,23 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper)
break;
}
/*AVC sample to NALU*/
- if (avccfg) {
- u32 j, nal_size, remain;
+ if (avccfg || svccfg || hevccfg) {
+ u32 j, nal_size, remain, nal_unit_size;
char *ptr = samp->data;
+ nal_unit_size = 0;
+ if (avccfg) nal_unit_size= avccfg->nal_unit_size;
+ else if (svccfg) nal_unit_size = svccfg->nal_unit_size;
+ else if (hevccfg) nal_unit_size = hevccfg->nal_unit_size;
remain = samp->dataLength;
while (remain) {
nal_size = 0;
- if (remainnal_unit_size){
- GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Sample %d (size %d): Corrupted NAL Unit: header size %d - bytes left %d\n", i+1, samp->dataLength, avccfg->nal_unit_size, remain) );
+ if (remaindataLength, nal_unit_size, remain) );
break;
}
- for (j=0; jnal_unit_size; j++) {
+ for (j=0; jnal_unit_size) nal_size<<=8;
+ if (j+1data, samp->dataLength);
+ if (!avccfg && !svccfg && !hevccfg) gf_bs_write_data(bs, samp->data, samp->dataLength);
gf_isom_sample_del(&samp);
gf_set_progress("Media Export", i+1, count);
if (dumper->flags & GF_EXPORT_DO_ABORT) break;
}
if (has_qcp_pad) gf_bs_write_u8(bs, 0);
-
+exit:
if (avccfg) gf_odf_avc_cfg_del(avccfg);
+ if (svccfg) gf_odf_avc_cfg_del(svccfg);
gf_bs_del(bs);
if (!is_stdout)
fclose(out);
@@ -1429,7 +1564,11 @@ static GF_Err MP4T_CopyTrack(GF_MediaExporter *dumper, GF_ISOFile *infile, u32 i
if (msubtype == GF_ISOM_SUBTYPE_MPEG4_CRYP) {
esd = gf_isom_get_esd(infile, inTrackNum, 1);
- } else if ((msubtype == GF_ISOM_SUBTYPE_AVC_H264) || (msubtype == GF_ISOM_SUBTYPE_AVC2_H264) ) {
+ } else if ((msubtype == GF_ISOM_SUBTYPE_AVC_H264)
+ || (msubtype == GF_ISOM_SUBTYPE_AVC2_H264)
+ || (msubtype == GF_ISOM_SUBTYPE_AVC3_H264)
+ || (msubtype == GF_ISOM_SUBTYPE_AVC4_H264)
+ ) {
return gf_isom_set_pl_indication(outfile, GF_ISOM_PL_VISUAL, 0x0F);
}
/*likely 3gp or any non-MPEG-4 isomedia file*/
@@ -1848,6 +1987,7 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc)
if (flags & GF_DIMS_UNIT_C) fprintf(nhml, " compressed=\"yes\"");
fprintf(nhml, ">");
if (uncompress && (flags & GF_DIMS_UNIT_C)) {
+#ifndef GPAC_DISABLE_ZLIB
char svg_data[2049];
int err;
u32 done = 0;
@@ -1874,6 +2014,14 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc)
}
inflateEnd(&d_stream);
}
+#else
+ GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Error: your version of GPAC was compile with no libz support."));
+ gf_bs_del(bs);
+ gf_isom_sample_del(&samp);
+ if (med) fclose(med);
+ fclose(nhml);
+ return GF_NOT_SUPPORTED;
+#endif
} else {
gf_fwrite(samp->data+pos+3, size-1, 1, nhml);
}
@@ -2028,6 +2176,7 @@ GF_Err gf_media_export_saf(GF_MediaExporter *dumper)
void m2ts_export_check(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
{
if (evt_type == GF_M2TS_EVT_PAT_REPEAT) ts->user = NULL;
+ else if (evt_type == GF_M2TS_EVT_PAT_FOUND) ts->segment_switch = 1;
}
void m2ts_export_dump(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
{
@@ -2073,11 +2222,12 @@ GF_Err gf_media_export_ts_native(GF_MediaExporter *dumper)
gf_m2ts_process_data(ts, data, (u32)size);
if (!ts->user) break;
}
- if (ts->user) {
+ if (!ts->segment_switch && ts->user) {
fclose(src);
gf_m2ts_demux_del(ts);
return gf_export_message(dumper, GF_URL_ERROR, "Cannot locate program association table");
}
+ ts->segment_switch = 0;
stream = NULL;
for (i=0; i
#include
#include
-/*since 0.2.2, we use zlib for xmt/x3d reading to handle gz files*/
-#include
#ifndef GPAC_DISABLE_MEDIA_IMPORT
@@ -71,7 +69,9 @@ static GF_Err gf_media_update_par(GF_ISOFile *file, u32 track)
if (e) return e;
stype = gf_isom_get_media_subtype(file, track, 1);
- if ((stype==GF_ISOM_SUBTYPE_AVC_H264) || (stype==GF_ISOM_SUBTYPE_AVC2_H264) ) {
+ if ((stype==GF_ISOM_SUBTYPE_AVC_H264) || (stype==GF_ISOM_SUBTYPE_AVC2_H264)
+ || (stype==GF_ISOM_SUBTYPE_AVC3_H264) || (stype==GF_ISOM_SUBTYPE_AVC4_H264)
+ ) {
s32 par_n, par_d;
GF_AVCConfig *avcc = gf_isom_avc_config_get(file, track, 1);
GF_AVCConfigSlot *slc = (GF_AVCConfigSlot *)gf_list_get(avcc->sequenceParameterSets, 0);
@@ -118,7 +118,7 @@ static void MP4T_RecomputeBitRate(GF_ISOFile *file, u32 track)
esd->decoderConfig->avgBitrate = 0;
esd->decoderConfig->maxBitrate = 0;
rate = max_rate = avg_rate = time_wnd = 0;
-
+
timescale = gf_isom_get_media_timescale(file, track);
count = gf_isom_get_sample_count(file, track);
for (i=0; iorig));
+ Bool sbr, ps;
GF_ISOSample *samp;
GF_ESD *origin_esd;
GF_InitialObjectDescriptor *iod;
@@ -1589,6 +1589,7 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import)
ps = 0;
sbr = 0;
sbr_sr = 0;
+ cur_extract_mode = gf_isom_get_nalu_extract_mode(import->orig, track_in);
iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(import->orig);
if (iod && (iod->tag != GF_ODF_IOD_TAG)) {
gf_odf_desc_del((GF_Descriptor *) iod);
@@ -1643,72 +1644,16 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import)
gf_odf_desc_del((GF_Descriptor *) iod);
- /*check if MPEG-4 or not - if crypted use clone track */
- is_clone = 0;
- stype = gf_isom_get_media_subtype(import->orig, track_in, 1);
- if ((stype==GF_ISOM_SUBTYPE_MPEG4) /*|| (stype==GF_ISOM_SUBTYPE_MPEG4_CRYP)*/) {
- track = gf_isom_new_track(import->dest, import->esd ? import->esd->ESID : 0, gf_isom_get_media_type(import->orig, track_in), gf_isom_get_media_timescale(import->orig, track_in));
- if (!track) {
- e = gf_isom_last_error(import->dest);
- goto exit;
- }
- gf_isom_set_track_enabled(import->dest, track, 1);
- if (import->esd && !import->esd->ESID) import->esd->ESID = gf_isom_get_track_id(import->dest, track);
- /*setup data ref*/
- urn = url = NULL;
- if (import->flags & GF_IMPORT_USE_DATAREF) {
- url = gf_isom_get_filename(import->orig);
- if (!gf_isom_is_self_contained(import->orig, track_in, 1)) {
- e = gf_isom_get_data_reference(import->orig, track_in, 1, &url, &urn);
- if (e) goto exit;
- }
- }
- e = gf_isom_new_mpeg4_description(import->dest, track, origin_esd, (char *) url, (char *) urn, &di);
- if (e) goto exit;
- /*copy over language*/
- lang[3] = 0;
- gf_isom_get_media_language(import->orig, track_in, lang);
- gf_isom_set_media_language(import->dest, track, lang);
+ e = gf_isom_clone_track(import->orig, track_in, import->dest, (import->flags & GF_IMPORT_USE_DATAREF), &track);
+ if (e) goto exit;
- } else {
- if (! (import->flags & GF_IMPORT_KEEP_ALL_TRACKS) ) {
- mstype = gf_isom_get_media_subtype(import->orig, track_in, 1);
- switch (mstype) {
- case GF_ISOM_SUBTYPE_MPEG4:
- case GF_ISOM_SUBTYPE_MPEG4_CRYP:
- case GF_ISOM_SUBTYPE_AVC_H264:
- case GF_ISOM_SUBTYPE_AVC2_H264:
- case GF_ISOM_SUBTYPE_SVC_H264:
- case GF_ISOM_SUBTYPE_3GP_H263:
- case GF_ISOM_SUBTYPE_3GP_AMR:
- case GF_ISOM_SUBTYPE_3GP_AMR_WB:
- case GF_ISOM_SUBTYPE_3GP_EVRC:
- case GF_ISOM_SUBTYPE_3GP_QCELP:
- case GF_ISOM_SUBTYPE_3GP_SMV:
- break;
- default:
- switch (mtype) {
- case GF_ISOM_MEDIA_HINT:
- case GF_ISOM_MEDIA_TEXT:
- case GF_ISOM_MEDIA_SUBT:
- break;
- default:
- return gf_import_message(import, GF_OK, "IsoMedia import - skipping track ID %d (unknown type \'%s\')", trackID, gf_4cc_to_str(mstype));
- }
- }
+ di = 1;
- }
- e = gf_isom_clone_track(import->orig, track_in, import->dest, (import->flags & GF_IMPORT_USE_DATAREF), &track);
- is_clone = 1;
- di = 1;
+ if (import->esd && import->esd->ESID) {
+ e = gf_isom_set_track_id(import->dest, track, import->esd->ESID);
if (e) goto exit;
-
- if (import->esd && import->esd->ESID) {
- e = gf_isom_set_track_id(import->dest, track, import->esd->ESID);
- if (e) goto exit;
- }
}
- if (e) goto exit;
+
import->final_trackID = gf_isom_get_track_id(import->dest, track);
if (import->esd && import->esd->dependsOnESID) {
gf_isom_set_track_reference(import->dest, track, GF_ISOM_REF_DECODE, import->esd->dependsOnESID);
@@ -1716,29 +1661,21 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import)
switch (mtype) {
case GF_ISOM_MEDIA_VISUAL:
- if (!is_clone) {
- gf_isom_set_visual_info(import->dest, track, di, w, h);
- gf_media_update_par(import->dest, track);
- }
- gf_import_message(import, GF_OK, "IsoMedia import - track ID %d - Video (size %d x %d)", trackID, w, h);
+ gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - Video (size %d x %d)", orig_name, trackID, w, h);
break;
case GF_ISOM_MEDIA_AUDIO:
{
- if (!is_clone) gf_isom_set_audio_info(import->dest, track, di, (sbr==2) ? sbr_sr : sr, (ch>1) ? 2 : 1, bps);
if (ps) {
- gf_import_message(import, GF_OK, "IsoMedia import - track ID %d - HE-AACv2 (SR %d - SBR-SR %d - %d channels)", trackID, sr, sbr_sr, ch);
+ gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - HE-AACv2 (SR %d - SBR-SR %d - %d channels)", orig_name, trackID, sr, sbr_sr, ch);
} else if (sbr) {
- gf_import_message(import, GF_OK, "IsoMedia import - track ID %d - HE-AAC (SR %d - SBR-SR %d - %d channels)", trackID, sr, sbr_sr, ch);
+ gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - HE-AAC (SR %d - SBR-SR %d - %d channels)", orig_name, trackID, sr, sbr_sr, ch);
} else {
- gf_import_message(import, GF_OK, "IsoMedia import - track ID %d - Audio (SR %d - %d channels)", trackID, sr, ch);
+ gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - Audio (SR %d - %d channels)", orig_name, trackID, sr, ch);
}
}
break;
case GF_ISOM_MEDIA_SUBPIC:
- if (!is_clone) {
- gf_isom_set_track_layout_info(import->dest, track, w << 16, h << 16, trans_x, trans_y, layer);
- }
- gf_import_message(import, GF_OK, "IsoMedia import - track ID %d - VobSub (size %d x %d)", trackID, w, h);
+ gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - VobSub (size %d x %d)", orig_name, trackID, w, h);
break;
default:
{
@@ -1746,14 +1683,13 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import)
mstype = gf_isom_get_mpeg4_subtype(import->orig, track_in, di);
if (!mstype) mstype = gf_isom_get_media_subtype(import->orig, track_in, di);
strcpy(szT, gf_4cc_to_str(mtype));
- gf_import_message(import, GF_OK, "IsoMedia import - track ID %d - media type \"%s:%s\"",
- trackID, szT, gf_4cc_to_str(mstype));
+ gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - media type \"%s:%s\"", orig_name, trackID, szT, gf_4cc_to_str(mstype));
}
break;
}
duration = (u64) (((Double)import->duration * gf_isom_get_media_timescale(import->orig, track_in)) / 1000);
-
+ gf_isom_set_nalu_extract_mode(import->orig, track_in, GF_ISOM_NALU_EXTRACT_INSPECT);
num_samples = gf_isom_get_sample_count(import->orig, track_in);
for (i=0; iflags & GF_IMPORT_USE_DATAREF) {
@@ -1808,6 +1744,7 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import)
exit:
if (origin_esd) gf_odf_desc_del((GF_Descriptor *) origin_esd);
+ gf_isom_set_nalu_extract_mode(import->orig, track_in, cur_extract_mode);
return e;
}
@@ -2478,6 +2415,12 @@ exit:
return e;
}
+
+#ifndef GPAC_DISABLE_ZLIB
+
+/*since 0.2.2, we use zlib for xmt/x3d reading to handle gz files*/
+#include
+
#define ZLIB_COMPRESS_SAFE 4
static GF_Err compress_sample_data(GF_ISOSample *samp, u32 *max_size, char **dict, u32 offset)
@@ -2534,6 +2477,8 @@ static GF_Err compress_sample_data(GF_ISOSample *samp, u32 *max_size, char **dic
return GF_OK;
}
+#endif /*GPAC_DISABLE_ZLIB*/
+
static void nhml_on_progress(void *cbk, u64 done, u64 tot)
{
gf_set_progress("NHML Loading", done, tot);
@@ -3003,6 +2948,7 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc)
}
if (compress) {
+#ifndef GPAC_DISABLE_ZLIB
e = compress_sample_data(samp, &max_size, use_dict ? &dictionary : NULL, is_dims ? 3 : 0);
if (e) goto exit;
if (is_dims) {
@@ -3010,6 +2956,11 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc)
gf_bs_write_u16(bs, samp->dataLength-2);
gf_bs_del(bs);
}
+#else
+ GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: your version of GPAC was compile with no libz support. Abort."));
+ e = GF_NOT_SUPPORTED;
+ goto exit;
+#endif
}
if (is_dims && (samp->dataLength > 0xFFFF)) {
e = gf_import_message(import, GF_BAD_PARAM, "DIMS import failure: sample data is too long - maximum size allowed: 65532 bytes");
@@ -3768,7 +3719,7 @@ GF_Err gf_media_avc_rewrite_samples(GF_ISOFile *file, u32 track, u32 prev_size,
#ifndef GPAC_DISABLE_AV_PARSERS
-GF_Err gf_import_h264(GF_MediaImporter *import)
+static GF_Err gf_import_avc_h264(GF_MediaImporter *import)
{
u64 nal_start, nal_end, total_size;
u32 nal_size, track, trackID, di, cur_samp, nb_i, nb_idr, nb_p, nb_b, nb_sp, nb_si, nb_sei, max_w, max_h, max_total_delay;
@@ -3837,7 +3788,7 @@ restart_import:
sei_recovery_frame_count = -1;
bs = gf_bs_from_file(mdia, GF_BITSTREAM_READ);
- if (!AVC_IsStartCode(bs)) {
+ if (!gf_media_nalu_is_start_code(bs)) {
e = gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Cannot find H264 start code");
goto exit;
}
@@ -3893,7 +3844,7 @@ restart_import:
while (gf_bs_available(bs)) {
u8 nal_hdr, skip_nal, is_subseq, add_sps;
- nal_size = AVC_NextStartCode(bs);
+ nal_size = gf_media_nalu_next_start_code_bs(bs);
if (nal_size>max_size) {
buffer = (char*)gf_realloc(buffer, sizeof(char)*nal_size);
@@ -3915,7 +3866,7 @@ restart_import:
avc.is_svc = 1;
}
- switch (AVC_ParseNALU(bs, nal_hdr, &avc)) {
+ switch (gf_media_avc_parse_nalu(bs, nal_hdr, &avc)) {
case 1:
flush_sample = 1;
break;
@@ -3933,7 +3884,7 @@ restart_import:
case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
is_subseq = 1;
case GF_AVC_NALU_SEQ_PARAM:
- idx = AVC_ReadSeqInfo(buffer+1/*skip NALU type*/, nal_size-1, &avc, is_subseq, NULL);
+ idx = gf_media_avc_read_sps(buffer, nal_size, &avc, is_subseq, NULL);
if (idx<0) {
if (avc.sps[0].profile_idc) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Error parsing SeqInfo"));
@@ -4050,7 +4001,7 @@ restart_import:
}
break;
case GF_AVC_NALU_PIC_PARAM:
- idx = AVC_ReadPictParamSet(buffer+1/*skip NALU type*/, nal_size-1, &avc);
+ idx = gf_media_avc_read_pps(buffer, nal_size, &avc);
if (idx<0) {
e = gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Error parsing Picture Param");
goto exit;
@@ -4075,12 +4026,15 @@ restart_import:
they will be moved to the SVC layer upon analysis of SVC slice. */
dstcfg = avccfg;
+ if (import->flags & GF_IMPORT_SVC_EXPLICIT)
+ dstcfg = svccfg;
+
gf_list_add(dstcfg->pictureParameterSets, slc);
}
break;
case GF_AVC_NALU_SEI:
if (avc.sps_active_idx != -1) {
- copy_size = AVC_ReformatSEI_NALU(buffer, nal_size, &avc);
+ copy_size = gf_media_avc_reformat_sei(buffer, nal_size, &avc);
if (copy_size)
nb_sei++;
}
@@ -4149,7 +4103,7 @@ restart_import:
break;
case GF_AVC_NALU_SEQ_PARAM_EXT:
- idx = AVC_ReadSeqParamSetExtId(buffer+1/*skip NALU type*/, nal_size-1);
+ idx = gf_media_avc_read_sps_ext(buffer, nal_size);
if (idx<0) {
e = gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Error parsing Sequence Param Extension");
goto exit;
@@ -4363,7 +4317,7 @@ restart_import:
if (first_nal) {
first_nal = 0;
if (avc.sei.recovery_point.valid || (import->flags & GF_IMPORT_FORCE_SYNC)) {
- Bool bIntraSlice = AVC_SliceIsIntra(&avc);
+ Bool bIntraSlice = gf_media_avc_slice_is_intra(&avc);
assert(avc.s_info.nal_unit_type!=GF_AVC_NALU_IDR_SLICE || bIntraSlice);
sei_recovery_frame_count = avc.sei.recovery_point.frame_cnt;
@@ -4380,7 +4334,7 @@ restart_import:
if (bIntraSlice && (import->flags & GF_IMPORT_FORCE_SYNC) && (sei_recovery_frame_count==0))
slice_force_ref = 1;
}
- sample_is_rap = AVC_SliceIsIDR(&avc);
+ sample_is_rap = gf_media_avc_slice_is_IDR(&avc);
}
if (avc.s_info.pocflags & GF_IMPORT_DO_ABORT) break;
/*consume next start code*/
- nal_start = AVC_NextStartCode(bs);
+ nal_start = gf_media_nalu_next_start_code_bs(bs);
if (nal_start) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[avc-h264] invalid nal_size (%u)? Skipping "LLU" bytes to reach next start code\n", nal_size, nal_start));
gf_bs_skip_bytes(bs, nal_start);
}
- nal_start = AVC_IsStartCode(bs);
+ nal_start = gf_media_nalu_is_start_code(bs);
if (!nal_start) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[avc-h264] error: no start code found ("LLU" bytes read out of "LLU") - leaving\n", gf_bs_get_position(bs), gf_bs_get_size(bs)));
break;
}
nal_start = gf_bs_get_position(bs);
}
-
+
/*final flush*/
if (sample_data) {
GF_ISOSample *samp = gf_isom_sample_new();
@@ -4644,157 +4598,901 @@ exit:
return e;
}
-#endif /*GPAC_DISABLE_AV_PARSERS*/
-#ifndef GPAC_DISABLE_OGG
+static GF_Err gf_import_hevc(GF_MediaImporter *import)
+{
+ u64 nal_start, nal_end, total_size;
+ u32 nal_size, track, trackID, di, cur_samp, nb_i, nb_idr, nb_p, nb_b, nb_sp, nb_si, nb_sei, max_w, max_h, max_total_delay;
+ s32 idx, sei_recovery_frame_count;
+ u64 duration;
+ GF_Err e;
+ FILE *mdia;
+ HEVCState hevc;
+ GF_AVCConfigSlot *slc;
+ GF_HEVCConfig *hevccfg;
+ GF_HEVCParamArray *spss, *ppss, *vpss;
+ GF_BitStream *bs;
+ GF_BitStream *sample_data;
+ Bool flush_sample, sample_is_rap, sample_has_islice, first_nal, slice_is_ref, has_cts_offset, is_paff, set_subsamples, slice_force_ref;
+ u32 ref_frame, timescale, copy_size, size_length, dts_inc;
+ s32 last_poc, max_last_poc, max_last_b_poc, poc_diff, prev_last_poc, min_poc, poc_shift;
+ Bool first_avc;
+ Bool use_opengop_gdr = 0;
-#define OGG_BUFFER_SIZE 4096
+ Double FPS;
+ char *buffer;
+ u32 max_size = 4096;
-Bool OGG_ReadPage(FILE *f_in, ogg_sync_state *oy, ogg_page *oggpage)
-{
- if (feof(f_in)) return 0;
- while (ogg_sync_pageout(oy, oggpage ) != 1 ) {
- char *buffer = ogg_sync_buffer(oy, OGG_BUFFER_SIZE);
- u32 bytes = fread(buffer, sizeof(char), OGG_BUFFER_SIZE, f_in);
- ogg_sync_wrote(oy, bytes);
- if (feof(f_in)) return 1;
+ if (import->flags & GF_IMPORT_PROBE_ONLY) {
+ import->nb_tracks = 1;
+ import->tk_info[0].track_num = 1;
+ import->tk_info[0].type = GF_ISOM_MEDIA_VISUAL;
+ import->tk_info[0].flags = GF_IMPORT_OVERRIDE_FPS | GF_IMPORT_FORCE_PACKED;
+ return GF_OK;
}
- return 1;
-}
-static u32 get_ogg_serial_no_for_stream(char *fileName, u32 stream_num, Bool is_video)
-{
- ogg_sync_state oy;
- u32 track, serial_no;
- ogg_page oggpage;
- ogg_packet oggpacket;
- ogg_stream_state os;
- FILE *f_in;
+ set_subsamples = (import->flags & GF_IMPORT_SET_SUBSAMPLES) ? 1 : 0;
- /*means first one*/
- if (!stream_num) return 0;
+ mdia = gf_f64_open(import->in_name, "rb");
+ if (!mdia) return gf_import_message(import, GF_URL_ERROR, "Cannot find file %s", import->in_name);
- f_in = gf_f64_open(fileName, "rb");
- if (!f_in) return 0;
+ //detect_fps = 1;
+ FPS = (Double) import->video_fps;
+ if (!FPS) {
+ FPS = GF_IMPORT_DEFAULT_FPS;
+ } else {
+ if (import->video_fps == GF_IMPORT_AUTO_FPS) {
+ import->video_fps = GF_IMPORT_DEFAULT_FPS; /*fps=auto is handled as auto-detection is h264*/
+ } else {
+ /*fps is forced by the caller*/
+ //detect_fps = 0;
+ }
+ }
+ get_video_timing(FPS, ×cale, &dts_inc);
- track = 0;
- serial_no = 0;
- ogg_sync_init(&oy);
- while (1) {
- if (!OGG_ReadPage(f_in, &oy, &oggpage)) break;
- if (!ogg_page_bos(&oggpage)) break;
- track ++;
- if (track != stream_num) continue;
+ poc_diff = 0;
- serial_no = ogg_page_serialno(&oggpage);
- ogg_stream_init(&os, serial_no);
- ogg_stream_pagein(&os, &oggpage);
- ogg_stream_packetpeek(&os, &oggpacket);
- if (is_video && (oggpacket.bytes >= 7) && !strncmp((char *)&oggpacket.packet[1], "theora", 6)) {
- ogg_stream_clear(&os);
- break;
- }
- if (!is_video && (oggpacket.bytes >= 7) && !strncmp((char *)&oggpacket.packet[1], "vorbis", 6)) {
- ogg_stream_clear(&os);
- break;
- }
- ogg_stream_clear(&os);
- serial_no = 0;
- }
- ogg_sync_clear(&oy);
- fclose(f_in);
- return serial_no;
-}
+//restart_import:
-GF_Err gf_import_ogg_video(GF_MediaImporter *import)
-{
- GF_Err e;
- ogg_sync_state oy;
- u32 di, track;
- u64 tot_size, done, duration;
- u32 w, h, fps_num, fps_den, keyframe_freq_force, theora_kgs, flag, dts_inc, timescale;
- Double FPS;
- Bool destroy_esd, go;
- u32 serial_no, sno, num_headers;
- ogg_packet oggpacket;
- ogg_page oggpage;
- ogg_stream_state os;
- oggpack_buffer opb;
- GF_BitStream *bs;
- FILE *f_in;
- GF_ISOSample *samp;
+ memset(&hevc, 0, sizeof(HEVCState));
+ hevc.sps_active_idx = -1;
+ hevccfg = gf_odf_hevc_cfg_new();
+ buffer = (char*)gf_malloc(sizeof(char) * max_size);
+ sample_data = NULL;
+ first_avc = 1;
+ sei_recovery_frame_count = -1;
+ spss = ppss = vpss = NULL;
+ bs = gf_bs_from_file(mdia, GF_BITSTREAM_READ);
+ if (!gf_media_nalu_is_start_code(bs)) {
+ e = gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Cannot find H264 start code");
+ goto exit;
+ }
- dts_inc = 0;
- /*assume audio or simple AV file*/
- if (import->flags & GF_IMPORT_PROBE_ONLY) {
- f_in = gf_f64_open(import->in_name, "rb");
- if (!f_in) return GF_URL_ERROR;
+ /*NALU size packing disabled*/
+ if (!(import->flags & GF_IMPORT_FORCE_PACKED)) size_length = 32;
+ /*if import in edit mode, use smallest NAL size and adjust on the fly*/
+ else if (gf_isom_get_mode(import->dest)!=GF_ISOM_OPEN_WRITE) size_length = 8;
+ else size_length = 32;
- import->nb_tracks = 0;
- go = 1;
- ogg_sync_init(&oy);
- while (go) {
- if (!OGG_ReadPage(f_in, &oy, &oggpage)) break;
+ trackID = 0;
+ e = GF_OK;
+ if (import->esd) trackID = import->esd->ESID;
- if (!ogg_page_bos(&oggpage)) {
- go = 0;
- continue;
- }
- serial_no = ogg_page_serialno(&oggpage);
- ogg_stream_init(&os, serial_no);
- ogg_stream_pagein(&os, &oggpage);
- ogg_stream_packetpeek(&os, &oggpacket);
+ track = gf_isom_new_track(import->dest, trackID, GF_ISOM_MEDIA_VISUAL, timescale);
+ if (!track) {
+ e = gf_isom_last_error(import->dest);
+ goto exit;
+ }
+ gf_isom_set_track_enabled(import->dest, track, 1);
+ if (import->esd && !import->esd->ESID) import->esd->ESID = gf_isom_get_track_id(import->dest, track);
+ import->final_trackID = gf_isom_get_track_id(import->dest, track);
+ if (import->esd && import->esd->dependsOnESID) {
+ gf_isom_set_track_reference(import->dest, track, GF_ISOM_REF_DECODE, import->esd->dependsOnESID);
+ }
- import->tk_info[import->nb_tracks].track_num = import->nb_tracks+1;
- if ((oggpacket.bytes >= 7) && !strncmp((char *)&oggpacket.packet[1], "theora", 6)) {
- import->tk_info[import->nb_tracks].type = GF_ISOM_MEDIA_VISUAL;
- import->tk_info[import->nb_tracks].flags = GF_IMPORT_OVERRIDE_FPS;
+ e = gf_isom_hevc_config_new(import->dest, track, hevccfg, NULL, NULL, &di);
+ if (e) goto exit;
- bs = gf_bs_new((char*)oggpacket.packet, oggpacket.bytes, GF_BITSTREAM_READ);
- gf_bs_read_int(bs, 80);
- import->tk_info[import->nb_tracks].video_info.width = gf_bs_read_u16(bs) << 4;
- import->tk_info[import->nb_tracks].video_info.height = gf_bs_read_u16(bs) << 4;
- gf_bs_read_int(bs, 64);
- fps_num = gf_bs_read_u32(bs);
- fps_den = gf_bs_read_u32(bs);
- gf_bs_del(bs);
- import->tk_info[import->nb_tracks].video_info.FPS = fps_num;
- import->tk_info[import->nb_tracks].video_info.FPS /= fps_den;
- import->tk_info[import->nb_tracks].media_type = GF_4CC('t','h','e','o');
- } else if ((oggpacket.bytes >= 7) && !strncmp((char *)&oggpacket.packet[1], "vorbis", 6)) {
- import->tk_info[import->nb_tracks].type = GF_ISOM_MEDIA_AUDIO;
- import->tk_info[import->nb_tracks].flags = 0;
- }
- ogg_stream_clear(&os);
- import->nb_tracks++;
- }
- ogg_sync_clear(&oy);
- fclose(f_in);
- return GF_OK;
- }
+ sample_data = NULL;
+ sample_is_rap = 0;
+ sample_has_islice = 0;
+ cur_samp = 0;
+ is_paff = 0;
+ total_size = gf_bs_get_size(bs);
+ nal_start = gf_bs_get_position(bs);
+ duration = (u64) ( ((Double)import->duration) * timescale / 1000.0);
- if (import->flags & GF_IMPORT_USE_DATAREF) return gf_import_message(import, GF_NOT_SUPPORTED, "Cannot use data referencing with OGG files");
+ nb_i = nb_idr = nb_p = nb_b = nb_sp = nb_si = nb_sei = 0;
+ max_w = max_h = 0;
+ first_nal = 1;
+ ref_frame = 0;
+ last_poc = max_last_poc = max_last_b_poc = prev_last_poc = 0;
+ max_total_delay = 0;
- sno = get_ogg_serial_no_for_stream(import->in_name, import->trackID, 1);
- /*not our stream*/
- if (!sno && import->trackID) return GF_OK;
+ gf_isom_set_cts_packing(import->dest, track, 1);
+ has_cts_offset = 0;
+ min_poc = 0;
+ poc_shift = 0;
- f_in = gf_f64_open(import->in_name, "rb");
- if (!f_in) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name);
+ while (gf_bs_available(bs)) {
+ s32 res;
+ u8 nal_unit_type, temporal_id;
+ Bool skip_nal, add_sps, is_slice;
+ nal_size = gf_media_nalu_next_start_code_bs(bs);
- e = GF_OK;
- done = 0;
- gf_f64_seek(f_in, 0, SEEK_END);
- tot_size = gf_f64_tell(f_in);
- gf_f64_seek(f_in, 0, SEEK_SET);
+ if (nal_size>max_size) {
+ buffer = (char*)gf_realloc(buffer, sizeof(char)*nal_size);
+ max_size = nal_size;
+ }
+ /*read the file, and work on a memory buffer*/
+ gf_bs_read_data(bs, buffer, nal_size);
- destroy_esd = 0;
- samp = gf_isom_sample_new();
+ gf_bs_seek(bs, nal_start);
- /*avoids gcc warnings*/
+ res = gf_media_hevc_parse_nalu(bs, &hevc, &nal_unit_type, &temporal_id);
+
+ skip_nal = 0;
+ copy_size = flush_sample = 0;
+ is_slice = 0;
+
+ switch (res) {
+ case 1:
+ flush_sample = 1;
+ break;
+ case -1:
+ gf_import_message(import, GF_OK, "Waring: Error parsing NAL unit");
+ skip_nal = 1;
+ break;
+ case -2:
+ skip_nal = 1;
+ break;
+ default:
+ break;
+ }
+ switch (nal_unit_type) {
+ case GF_HEVC_NALU_VID_PARAM:
+ idx = gf_media_hevc_read_vps(buffer, nal_size , &hevc);
+ if (idx<0) {
+ e = gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Error parsing Picture Param");
+ goto exit;
+ }
+ /*if we get twice the same VPS put in the the bitstream and set array_completeness to 0 ...*/
+ if (hevc.vps[idx].state == 2) {
+ copy_size = nal_size;
+ assert(vpss);
+ vpss->array_completeness = 0;
+ }
+
+ if (hevc.vps[idx].state==1) {
+ hevc.vps[idx].state = 2;
+
+ hevccfg->avgFrameRate = hevc.vps[idx].rates[0].avg_pic_rate;
+ hevccfg->constantFrameRate = hevc.vps[idx].rates[0].constand_pic_rate_idc;
+ hevccfg->numTemporalLayers = hevc.vps[idx].max_sub_layer;
+
+ if (!vpss) {
+ GF_SAFEALLOC(vpss, GF_HEVCParamArray);
+ vpss->nalus = gf_list_new();
+ gf_list_add(hevccfg->param_array, vpss);
+ vpss->array_completeness = 1;
+ vpss->type = GF_HEVC_NALU_VID_PARAM;
+ }
+
+ slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ slc->size = nal_size;
+ slc->id = idx;
+ slc->data = (char*)gf_malloc(sizeof(char)*slc->size);
+ memcpy(slc->data, buffer, sizeof(char)*slc->size);
+
+ gf_list_add(vpss->nalus, slc);
+ }
+ break;
+ case GF_HEVC_NALU_SEQ_PARAM:
+ idx = gf_media_hevc_read_sps(buffer, nal_size, &hevc);
+ if (idx<0) {
+ e = gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Error parsing SeqInfo");
+ goto exit;
+ }
+ add_sps = 0;
+ if ((hevc.sps[idx].state & AVC_SPS_PARSED) && !(hevc.sps[idx].state & AVC_SPS_DECLARED)) {
+ hevc.sps[idx].state |= AVC_SPS_DECLARED;
+ add_sps = 1;
+ }
+
+ /*if we get twice the same VPS put in the the bitstream and set array_completeness to 0 ...*/
+ if (hevc.sps[idx].state & AVC_SUBSPS_DECLARED) {
+ if (import->flags & GF_IMPORT_SVC_NONE) {
+ copy_size = 0;
+ } else {
+ copy_size = nal_size;
+ assert(spss);
+ spss->array_completeness = 0;
+ }
+ }
+
+ if (add_sps) {
+ hevccfg->configurationVersion = 1;
+ hevccfg->profile_space = hevc.sps[idx].ptl.profile_space;
+ hevccfg->profile_idc = hevc.sps[idx].ptl.profile_idc;
+ hevccfg->constraint_indicator_flags = 0;
+ hevccfg->level_idc = hevc.sps[idx].ptl.level_idc;
+ hevccfg->profile_compatibility_indications = hevc.sps[idx].ptl.profile_compatibility_flag;
+ hevccfg->chromaFormat = hevc.sps[idx].chroma_format_idc;
+ hevccfg->luma_bit_depth = hevc.sps[idx].bit_depth_luma;
+ hevccfg->chroma_bit_depth = hevc.sps[idx].bit_depth_chroma;
+
+ /*
+ todo FPS detection
+
+ timescale = 2 * avc.sps[idx].vui.time_scale;
+ dts_inc = 2 * avc.sps[idx].vui.num_units_in_tick * DeltaTfiDivisorIdx;
+ FPS = (Double)timescale / dts_inc;
+ detect_fps = 0;
+ gf_isom_remove_track(import->dest, track);
+ if (sample_data) gf_bs_del(sample_data);
+ gf_odf_avc_cfg_del(avccfg);
+ avccfg = NULL;
+ gf_free(buffer);
+ buffer = NULL;
+ gf_bs_del(bs);
+ bs = NULL;
+ gf_f64_seek(mdia, 0, SEEK_SET);
+ goto restart_import;
+ }
+ */
+
+ if (!spss) {
+ GF_SAFEALLOC(spss, GF_HEVCParamArray);
+ spss->nalus = gf_list_new();
+ gf_list_add(hevccfg->param_array, spss);
+ spss->array_completeness = 1;
+ spss->type = GF_HEVC_NALU_SEQ_PARAM;
+ }
+
+ slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ slc->size = nal_size;
+ slc->id = idx;
+ slc->data = (char*)gf_malloc(sizeof(char)*slc->size);
+ memcpy(slc->data, buffer, sizeof(char)*slc->size);
+ gf_list_add(spss->nalus, slc);
+
+ if (first_avc) {
+ first_avc = 0;
+ gf_import_message(import, GF_OK, "AVC-H264 import - frame size %d x %d at %02.3f FPS", hevc.sps[idx].width, hevc.sps[idx].height, FPS);
+ }
+
+ if ((max_w <= hevc.sps[idx].width) && (max_h <= hevc.sps[idx].height)) {
+ max_w = hevc.sps[idx].width;
+ max_h = hevc.sps[idx].height;
+ }
+ }
+ break;
+
+ case GF_HEVC_NALU_PIC_PARAM:
+ idx = gf_media_hevc_read_pps(buffer, nal_size, &hevc);
+ if (idx<0) {
+ e = gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Error parsing Picture Param");
+ goto exit;
+ }
+ /*if we get twice the same VPS put in the the bitstream and set array_completeness to 0 ...*/
+ if (hevc.pps[idx].state == 2) {
+ copy_size = nal_size;
+ assert(ppss);
+ ppss->array_completeness = 0;
+ }
+
+ if (hevc.pps[idx].state==1) {
+ hevc.pps[idx].state = 2;
+
+ if (!ppss) {
+ GF_SAFEALLOC(ppss, GF_HEVCParamArray);
+ ppss->nalus = gf_list_new();
+ gf_list_add(hevccfg->param_array, ppss);
+ ppss->array_completeness = 1;
+ ppss->type = GF_HEVC_NALU_PIC_PARAM;
+ }
+
+ slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ slc->size = nal_size;
+ slc->id = idx;
+ slc->data = (char*)gf_malloc(sizeof(char)*slc->size);
+ memcpy(slc->data, buffer, sizeof(char)*slc->size);
+
+ gf_list_add(ppss->nalus, slc);
+ }
+ break;
+ case GF_HEVC_NALU_SEI_PREFIX:
+ if (hevc.sps_active_idx != -1) {
+ /*TODO*/
+ //copy_size = gf_media_avc_reformat_sei(buffer, nal_size, &hevc);
+ copy_size = nal_size;
+ if (copy_size)
+ nb_sei++;
+ }
+ break;
+
+ /*slice_layer_rbsp*/
+// case GF_HEVC_NALU_SLICE_STSA_N:
+// case GF_HEVC_NALU_SLICE_STSA_R:
+ case GF_HEVC_NALU_SLICE_RADL_N:
+// case GF_HEVC_NALU_SLICE_RADL_R:
+ case GF_HEVC_NALU_SLICE_RASL_N:
+// case GF_HEVC_NALU_SLICE_RASL_R:
+ is_slice = 1;
+ if (! skip_nal) {
+ copy_size = nal_size;
+ }
+ break;
+
+ /*slice_segment_layer_rbsp*/
+ case GF_HEVC_NALU_SLICE_STSA_N:
+ case GF_HEVC_NALU_SLICE_STSA_R:
+ case GF_HEVC_NALU_SLICE_RADL_R:
+ case GF_HEVC_NALU_SLICE_RASL_R:
+ case GF_HEVC_NALU_SLICE_TRAIL_N:
+ case GF_HEVC_NALU_SLICE_TRAIL_R:
+ case GF_HEVC_NALU_SLICE_TSA_N:
+ case GF_HEVC_NALU_SLICE_TSA_R:
+ case GF_HEVC_NALU_SLICE_BLA_W_LP:
+ case GF_HEVC_NALU_SLICE_BLA_W_DLP:
+ case GF_HEVC_NALU_SLICE_BLA_N_LP:
+ case GF_HEVC_NALU_SLICE_IDR_W_DLP:
+ case GF_HEVC_NALU_SLICE_IDR_N_LP:
+ case GF_HEVC_NALU_SLICE_CRA:
+ is_slice = 1;
+ if (! skip_nal) {
+ copy_size = nal_size;
+ switch (hevc.s_info.slice_type) {
+ case GF_HEVC_TYPE_P: nb_p++; break;
+ case GF_HEVC_TYPE_I: nb_i++;
+ sample_has_islice = 1;
+ break;
+ case GF_HEVC_TYPE_B: nb_b++; break;
+ }
+ }
+ break;
+
+ /*remove*/
+ case GF_HEVC_NALU_ACCESS_UNIT:
+ case GF_HEVC_NALU_FILLER_DATA:
+ case GF_HEVC_NALU_END_OF_SEQ:
+ case GF_HEVC_NALU_END_OF_STREAM:
+ break;
+
+ default:
+ gf_import_message(import, GF_OK, "WARNING: NAL Unit type %d not handled - adding", nal_unit_type);
+ copy_size = nal_size;
+ break;
+ }
+
+ if (!nal_size) break;
+
+ if (flush_sample && sample_data) {
+ GF_ISOSample *samp = gf_isom_sample_new();
+ samp->DTS = (u64)dts_inc*cur_samp;
+ samp->IsRAP = sample_is_rap;
+ if (!sample_is_rap) {
+ if (sample_has_islice && (import->flags & GF_IMPORT_FORCE_SYNC) && (sei_recovery_frame_count==0)) {
+ samp->IsRAP = 1;
+ if (!use_opengop_gdr) {
+ use_opengop_gdr = 1;
+ GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[AVC Import] Forcing non-IDR samples with I slices to be marked as sync points - resulting file will not be ISO conformant\n"));
+ }
+ }
+ }
+ gf_bs_get_content(sample_data, &samp->data, &samp->dataLength);
+ gf_bs_del(sample_data);
+ sample_data = NULL;
+
+
+
+ /*CTS recomuting is much trickier than with MPEG-4 ASP due to b-slice used as references - we therefore
+ store the POC as the CTS offset and update the whole table at the end*/
+ samp->CTS_Offset = last_poc - poc_shift;
+ assert(last_poc >= poc_shift);
+ e = gf_isom_add_sample(import->dest, track, di, samp);
+ if (e) goto exit;
+
+ cur_samp++;
+
+ /*write sampleGroups info*/
+ if (!samp->IsRAP && (sei_recovery_frame_count>=0)) {
+ /*generic GDR*/
+ if (sei_recovery_frame_count) {
+ if (!use_opengop_gdr) use_opengop_gdr = 1;
+ e = gf_isom_set_sample_roll_group(import->dest, track, cur_samp, (s16) sei_recovery_frame_count);
+ }
+ /*open-GOP*/
+ else if (sample_has_islice) {
+ if (!use_opengop_gdr) use_opengop_gdr = 2;
+ e = gf_isom_set_sample_rap_group(import->dest, track, cur_samp, 0);
+ }
+ if (e) goto exit;
+ }
+
+ gf_isom_sample_del(&samp);
+ gf_set_progress("Importing AVC-H264", (u32) (nal_start/1024), (u32) (total_size/1024) );
+ first_nal = 1;
+
+ if (min_poc > last_poc)
+ min_poc = last_poc;
+
+ sample_has_islice = 0;
+ sei_recovery_frame_count = -1;
+ }
+
+ if (copy_size) {
+ if ((size_length<32) && ( (u32) (1<dest, track, size_length, size_length+diff_size);
+
+ /*rewrite current sample*/
+ if (sample_data) {
+ char *sd;
+ u32 sd_l;
+ GF_BitStream *prev_sd;
+ gf_bs_get_content(sample_data, &sd, &sd_l);
+ gf_bs_del(sample_data);
+ sample_data = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
+ prev_sd = gf_bs_new(sd, sd_l, GF_BITSTREAM_READ);
+ while (gf_bs_available(prev_sd)) {
+ char *buf;
+ u32 s = gf_bs_read_int(prev_sd, size_length);
+ gf_bs_write_int(sample_data, s, size_length+diff_size);
+ buf = (char*)gf_malloc(sizeof(char)*s);
+ gf_bs_read_data(prev_sd, buf, s);
+ gf_bs_write_data(sample_data, buf, s);
+ gf_free(buf);
+ }
+ gf_bs_del(prev_sd);
+ gf_free(sd);
+ }
+ size_length+=diff_size;
+
+ }
+ if (!sample_data) sample_data = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
+ gf_bs_write_int(sample_data, copy_size, size_length);
+ gf_bs_write_data(sample_data, buffer, copy_size);
+
+ if (set_subsamples) {
+ /* use the res and priority value of last prefix NALU */
+ gf_isom_add_subsample(import->dest, track, cur_samp+1, copy_size+size_length/8, 0, 0, 0);
+ }
+
+ if (is_slice) {
+ slice_is_ref = gf_media_hevc_slice_is_IDR(&hevc);
+ if (slice_is_ref)
+ nb_idr++;
+ slice_force_ref = 0;
+
+ /*we only indicate TRUE IDRs for sync samples (cf AVC file format spec).
+ SEI recovery should be used to build sampleToGroup & RollRecovery tables*/
+ if (first_nal) {
+ first_nal = 0;
+ if (hevc.sei.recovery_point.valid || (import->flags & GF_IMPORT_FORCE_SYNC)) {
+ Bool bIntraSlice = gf_media_hevc_slice_is_intra(&hevc);
+ assert(hevc.s_info.nal_unit_type!=GF_AVC_NALU_IDR_SLICE || bIntraSlice);
+
+ sei_recovery_frame_count = hevc.sei.recovery_point.frame_cnt;
+
+ /*we allow to mark I-frames as sync on open-GOPs (with sei_recovery_frame_count=0) when forcing sync even when the SEI RP is not available*/
+ if (!hevc.sei.recovery_point.valid && bIntraSlice) {
+ sei_recovery_frame_count = 0;
+ if (use_opengop_gdr == 1) {
+ use_opengop_gdr = 2; /*avoid message flooding*/
+ GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[AVC Import] No valid SEI Recovery Point found although needed - forcing\n"));
+ }
+ }
+ hevc.sei.recovery_point.valid = 0;
+ if (bIntraSlice && (import->flags & GF_IMPORT_FORCE_SYNC) && (sei_recovery_frame_count==0))
+ slice_force_ref = 1;
+ }
+ sample_is_rap = gf_media_hevc_slice_is_IDR(&hevc);
+ }
+
+ if (hevc.s_info.pocdest, track, j, NULL, NULL);
+ if (!samp) break;
+ samp->CTS_Offset += poc_shift;
+ samp->CTS_Offset -= hevc.s_info.poc;
+ gf_isom_modify_cts_offset(import->dest, track, j, samp->CTS_Offset);
+ gf_isom_sample_del(&samp);
+ }
+ }
+ poc_shift = hevc.s_info.poc;
+ }
+
+ /*if #pics, compute smallest POC increase*/
+ if (hevc.s_info.poc != last_poc) {
+ if (!poc_diff || (poc_diff > abs(hevc.s_info.poc-last_poc))) {
+ poc_diff = abs(hevc.s_info.poc - last_poc);/*ideally we would need to start the parsing again as poc_diff helps computing max_total_delay*/
+ }
+ last_poc = hevc.s_info.poc;
+ }
+
+ /*ref slice, reset poc*/
+ if (slice_is_ref) {
+ ref_frame = cur_samp+1;
+ max_last_poc = last_poc = max_last_b_poc = 0;
+ poc_shift = 0;
+ }
+ /*forced ref slice*/
+ else if (slice_force_ref) {
+ ref_frame = cur_samp+1;
+ /*adjust POC shift as sample will now be marked as sync, so wo must store poc as if IDR (eg POC=0) for our CTS offset computing to be correct*/
+ poc_shift = hevc.s_info.poc;
+ }
+ /*strictly less - this is a new P slice*/
+ else if (max_last_poclast_poc) {
+ /*need to store TS offsets*/
+ has_cts_offset = 1;
+ switch (hevc.s_info.slice_type) {
+ case GF_AVC_TYPE_B:
+ case GF_AVC_TYPE2_B:
+ if (!max_last_b_poc) {
+ max_last_b_poc = last_poc;
+ }
+ /*if same poc than last max, this is a B-slice*/
+ else if (last_poc>max_last_b_poc) {
+ max_last_b_poc = last_poc;
+ }
+ /*otherwise we had a B-slice reference: do nothing*/
+
+ break;
+ }
+ }
+
+ /*compute max delay (applicable when B slice are present)*/
+ if (ref_frame && poc_diff && (s32)(cur_samp-(ref_frame-1)-last_poc/poc_diff)>(s32)max_total_delay) {
+ max_total_delay = cur_samp - (ref_frame-1) - last_poc/poc_diff;
+ }
+ }
+ }
+
+ gf_bs_align(bs);
+ nal_end = gf_bs_get_position(bs);
+ assert(nal_start <= nal_end);
+ assert(nal_end <= nal_start + nal_size);
+ if (nal_end != nal_start + nal_size)
+ gf_bs_seek(bs, nal_start + nal_size);
+
+ if (!gf_bs_available(bs)) break;
+ if (duration && (dts_inc*cur_samp > duration)) break;
+ if (import->flags & GF_IMPORT_DO_ABORT) break;
+
+ /*consume next start code*/
+ nal_start = gf_media_nalu_next_start_code_bs(bs);
+ if (nal_start) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[avc-h264] invalid nal_size (%u)? Skipping "LLU" bytes to reach next start code\n", nal_size, nal_start));
+ gf_bs_skip_bytes(bs, nal_start);
+ }
+ nal_start = gf_media_nalu_is_start_code(bs);
+ if (!nal_start) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[avc-h264] error: no start code found ("LLU" bytes read out of "LLU") - leaving\n", gf_bs_get_position(bs), gf_bs_get_size(bs)));
+ break;
+ }
+ nal_start = gf_bs_get_position(bs);
+ }
+
+ /*final flush*/
+ if (sample_data) {
+ GF_ISOSample *samp = gf_isom_sample_new();
+ samp->DTS = (u64)dts_inc*cur_samp;
+ samp->IsRAP = sample_is_rap;
+ if (!sample_is_rap && sample_has_islice && (import->flags & GF_IMPORT_FORCE_SYNC)) {
+ samp->IsRAP = 1;
+ }
+ /*we store the frame order (based on the POC) as the CTS offset and update the whole table at the end*/
+ samp->CTS_Offset = last_poc - poc_shift;
+ gf_bs_get_content(sample_data, &samp->data, &samp->dataLength);
+ gf_bs_del(sample_data);
+ sample_data = NULL;
+ e = gf_isom_add_sample(import->dest, track, di, samp);
+ if (e) goto exit;
+ gf_isom_sample_del(&samp);
+ gf_set_progress("Importing AVC-H264", (u32) cur_samp, cur_samp+1);
+ cur_samp++;
+ }
+
+
+ /*recompute all CTS offsets*/
+ if (has_cts_offset) {
+ u32 i, last_cts_samp;
+ u64 last_dts, max_cts;
+ if (!poc_diff) poc_diff = 1;
+ /*no b-frame references, no need to cope with negative poc*/
+ if (!max_total_delay) {
+ min_poc=0;
+ max_total_delay = 1;
+ }
+ cur_samp = gf_isom_get_sample_count(import->dest, track);
+ min_poc *= -1;
+ last_dts = 0;
+ max_cts = 0;
+ last_cts_samp = 0;
+
+ for (i=0; idest, track, i+1, NULL, NULL);
+ /*poc re-init (RAP and POC to 0, otherwise that's SEI recovery), update base DTS*/
+ if (samp->IsRAP /*&& !samp->CTS_Offset*/)
+ last_dts = samp->DTS * (1+is_paff);
+
+ /*CTS offset is frame POC (refers to last IDR)*/
+ cts = (min_poc + (s32) samp->CTS_Offset) * dts_inc/poc_diff + (u32) last_dts;
+
+ /*if PAFF, 2 pictures (eg poc) <=> 1 aggregated frame (eg sample), divide by 2*/
+ if (is_paff) {
+ cts /= 2;
+ /*in some cases the poc is not on the top field - if that is the case, round up*/
+ if (cts%dts_inc) {
+ cts = ((cts/dts_inc)+1)*dts_inc;
+ }
+ }
+
+ /*B-frames offset*/
+ cts += (u32) (max_total_delay*dts_inc);
+
+ samp->CTS_Offset = (u32) (cts - samp->DTS);
+
+ if (max_cts < samp->DTS + samp->CTS_Offset) {
+ max_cts = samp->DTS + samp->CTS_Offset;
+ last_cts_samp = i;
+ }
+ /*this should never happen, however some streams seem to do weird POC increases (cf sorenson streams, last 2 frames),
+ this should hopefully take care of some bugs and ensure proper CTS...*/
+ if ((s32)samp->CTS_Offset<0) {
+ u32 j, k;
+ samp->CTS_Offset = 0;
+ gf_isom_modify_cts_offset(import->dest, track, i+1, samp->CTS_Offset);
+ for (j=last_cts_samp; jdest, track, j+1, NULL, NULL);
+ for (k=j+1; k<=i; k++) {
+ GF_ISOSample *bsamp = gf_isom_get_sample_info(import->dest, track, k+1, NULL, NULL);
+ if (asamp->CTS_Offset+asamp->DTS==bsamp->CTS_Offset+bsamp->DTS) {
+ max_cts += dts_inc;
+ bsamp->CTS_Offset = (u32) (max_cts - bsamp->DTS);
+ gf_isom_modify_cts_offset(import->dest, track, k+1, bsamp->CTS_Offset);
+ }
+ gf_isom_sample_del(&bsamp);
+ }
+ gf_isom_sample_del(&asamp);
+ }
+ max_cts = samp->DTS + samp->CTS_Offset;
+ } else {
+ gf_isom_modify_cts_offset(import->dest, track, i+1, samp->CTS_Offset);
+ }
+ gf_isom_sample_del(&samp);
+ }
+ /*and repack table*/
+ gf_isom_set_cts_packing(import->dest, track, 0);
+ } else {
+ gf_isom_remove_cts_info(import->dest, track);
+ }
+
+ gf_set_progress("Importing AVC-H264", (u32) cur_samp, cur_samp);
+
+ gf_isom_set_visual_info(import->dest, track, di, max_w, max_h);
+ hevccfg->nal_unit_size = size_length/8;
+
+ gf_isom_hevc_config_update(import->dest, track, 1, hevccfg);
+ gf_media_update_par(import->dest, track);
+ MP4T_RecomputeBitRate(import->dest, track);
+
+// gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_VISUAL, 0x15);
+ gf_isom_set_brand_info(import->dest, GF_ISOM_BRAND_ISO4, 1);
+ gf_isom_modify_alternate_brand(import->dest, GF_ISOM_BRAND_ISOM, 0);
+ gf_isom_modify_alternate_brand(import->dest, GF_4CC('h','v','c','1'), 1);
+
+ if (!vpss || !ppss || !spss) {
+ e = gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Import results: No SPS or PPS found in the bitstream ! Nothing imported\n");
+ } else {
+ if (nb_sp || nb_si) {
+ gf_import_message(import, GF_OK, "AVC Import results: %d samples - Slices: %d I %d P %d B %d SP %d SI - %d SEI - %d IDR",
+ cur_samp, nb_i, nb_p, nb_b, nb_sp, nb_si, nb_sei, nb_idr);
+ } else {
+ gf_import_message(import, GF_OK, "AVC Import results: %d samples - Slices: %d I %d P %d B - %d SEI - %d IDR",
+ cur_samp, nb_i, nb_p, nb_b, nb_sei, nb_idr);
+ }
+
+ if (max_total_delay>1) {
+ gf_import_message(import, GF_OK, "Stream uses forward prediction - stream CTS offset: %d frames", max_total_delay);
+ }
+ }
+
+ if (use_opengop_gdr==2) {
+ gf_import_message(import, GF_OK, "OpenGOP detected - adjusting file brand");
+ gf_isom_modify_alternate_brand(import->dest, GF_4CC('i', 's', 'o', '6'), 1);
+ }
+
+ /*rewrite ESD*/
+ if (import->esd) {
+ if (!import->esd->slConfig) import->esd->slConfig = (GF_SLConfig*) gf_odf_desc_new(GF_ODF_SLC_TAG);
+ import->esd->slConfig->predefined = 2;
+ import->esd->slConfig->timestampResolution = timescale;
+ if (import->esd->decoderConfig) gf_odf_desc_del((GF_Descriptor *)import->esd->decoderConfig);
+ import->esd->decoderConfig = gf_isom_get_decoder_config(import->dest, track, 1);
+ gf_isom_change_mpeg4_description(import->dest, track, 1, import->esd);
+ }
+
+exit:
+ if (sample_data) gf_bs_del(sample_data);
+ gf_odf_hevc_cfg_del(hevccfg);
+ gf_free(buffer);
+ gf_bs_del(bs);
+ fclose(mdia);
+ return e;
+}
+
+#endif /*GPAC_DISABLE_AV_PARSERS*/
+
+#ifndef GPAC_DISABLE_OGG
+
+#define OGG_BUFFER_SIZE 4096
+
+Bool OGG_ReadPage(FILE *f_in, ogg_sync_state *oy, ogg_page *oggpage)
+{
+ if (feof(f_in)) return 0;
+ while (ogg_sync_pageout(oy, oggpage ) != 1 ) {
+ char *buffer = ogg_sync_buffer(oy, OGG_BUFFER_SIZE);
+ u32 bytes = fread(buffer, sizeof(char), OGG_BUFFER_SIZE, f_in);
+ ogg_sync_wrote(oy, bytes);
+ if (feof(f_in)) return 1;
+ }
+ return 1;
+}
+
+static u32 get_ogg_serial_no_for_stream(char *fileName, u32 stream_num, Bool is_video)
+{
+ ogg_sync_state oy;
+ u32 track, serial_no;
+ ogg_page oggpage;
+ ogg_packet oggpacket;
+ ogg_stream_state os;
+ FILE *f_in;
+
+ /*means first one*/
+ if (!stream_num) return 0;
+
+ f_in = gf_f64_open(fileName, "rb");
+ if (!f_in) return 0;
+
+ track = 0;
+ serial_no = 0;
+ ogg_sync_init(&oy);
+ while (1) {
+ if (!OGG_ReadPage(f_in, &oy, &oggpage)) break;
+ if (!ogg_page_bos(&oggpage)) break;
+ track ++;
+ if (track != stream_num) continue;
+
+ serial_no = ogg_page_serialno(&oggpage);
+ ogg_stream_init(&os, serial_no);
+ ogg_stream_pagein(&os, &oggpage);
+ ogg_stream_packetpeek(&os, &oggpacket);
+
+ if (is_video && (oggpacket.bytes >= 7) && !strncmp((char *)&oggpacket.packet[1], "theora", 6)) {
+ ogg_stream_clear(&os);
+ break;
+ }
+ if (!is_video && (oggpacket.bytes >= 7) && !strncmp((char *)&oggpacket.packet[1], "vorbis", 6)) {
+ ogg_stream_clear(&os);
+ break;
+ }
+ ogg_stream_clear(&os);
+ serial_no = 0;
+ }
+ ogg_sync_clear(&oy);
+ fclose(f_in);
+ return serial_no;
+}
+
+GF_Err gf_import_ogg_video(GF_MediaImporter *import)
+{
+ GF_Err e;
+ ogg_sync_state oy;
+ u32 di, track;
+ u64 tot_size, done, duration;
+ u32 w, h, fps_num, fps_den, keyframe_freq_force, theora_kgs, flag, dts_inc, timescale;
+ Double FPS;
+ Bool destroy_esd, go;
+ u32 serial_no, sno, num_headers;
+ ogg_packet oggpacket;
+ ogg_page oggpage;
+ ogg_stream_state os;
+ oggpack_buffer opb;
+ GF_BitStream *bs;
+ FILE *f_in;
+ GF_ISOSample *samp;
+
+
+ dts_inc = 0;
+ /*assume audio or simple AV file*/
+ if (import->flags & GF_IMPORT_PROBE_ONLY) {
+ f_in = gf_f64_open(import->in_name, "rb");
+ if (!f_in) return GF_URL_ERROR;
+
+ import->nb_tracks = 0;
+ go = 1;
+ ogg_sync_init(&oy);
+ while (go) {
+ if (!OGG_ReadPage(f_in, &oy, &oggpage)) break;
+
+ if (!ogg_page_bos(&oggpage)) {
+ go = 0;
+ continue;
+ }
+ serial_no = ogg_page_serialno(&oggpage);
+ ogg_stream_init(&os, serial_no);
+ ogg_stream_pagein(&os, &oggpage);
+ ogg_stream_packetpeek(&os, &oggpacket);
+
+ import->tk_info[import->nb_tracks].track_num = import->nb_tracks+1;
+ if ((oggpacket.bytes >= 7) && !strncmp((char *)&oggpacket.packet[1], "theora", 6)) {
+ import->tk_info[import->nb_tracks].type = GF_ISOM_MEDIA_VISUAL;
+ import->tk_info[import->nb_tracks].flags = GF_IMPORT_OVERRIDE_FPS;
+
+ bs = gf_bs_new((char*)oggpacket.packet, oggpacket.bytes, GF_BITSTREAM_READ);
+ gf_bs_read_int(bs, 80);
+ import->tk_info[import->nb_tracks].video_info.width = gf_bs_read_u16(bs) << 4;
+ import->tk_info[import->nb_tracks].video_info.height = gf_bs_read_u16(bs) << 4;
+ gf_bs_read_int(bs, 64);
+ fps_num = gf_bs_read_u32(bs);
+ fps_den = gf_bs_read_u32(bs);
+ gf_bs_del(bs);
+ import->tk_info[import->nb_tracks].video_info.FPS = fps_num;
+ import->tk_info[import->nb_tracks].video_info.FPS /= fps_den;
+ import->tk_info[import->nb_tracks].media_type = GF_4CC('t','h','e','o');
+ } else if ((oggpacket.bytes >= 7) && !strncmp((char *)&oggpacket.packet[1], "vorbis", 6)) {
+ import->tk_info[import->nb_tracks].type = GF_ISOM_MEDIA_AUDIO;
+ import->tk_info[import->nb_tracks].flags = 0;
+ }
+ ogg_stream_clear(&os);
+ import->nb_tracks++;
+ }
+ ogg_sync_clear(&oy);
+ fclose(f_in);
+ return GF_OK;
+ }
+
+ if (import->flags & GF_IMPORT_USE_DATAREF) return gf_import_message(import, GF_NOT_SUPPORTED, "Cannot use data referencing with OGG files");
+
+ sno = get_ogg_serial_no_for_stream(import->in_name, import->trackID, 1);
+ /*not our stream*/
+ if (!sno && import->trackID) return GF_OK;
+
+ f_in = gf_f64_open(import->in_name, "rb");
+ if (!f_in) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name);
+
+ e = GF_OK;
+ done = 0;
+ gf_f64_seek(f_in, 0, SEEK_END);
+ tot_size = gf_f64_tell(f_in);
+ gf_f64_seek(f_in, 0, SEEK_SET);
+
+
+ destroy_esd = 0;
+ samp = gf_isom_sample_new();
+
+ /*avoids gcc warnings*/
duration = 0;
FPS = 0;
num_headers = w = h = track = 0;
@@ -5395,6 +6093,9 @@ typedef struct
#ifndef GPAC_DISABLE_AV_PARSERS
GF_AVCConfig *avccfg;
AVCState avc;
+
+ GF_HEVCConfig *hevccfg;
+ HEVCState hevc;
#endif
Bool force_next_au_start;
Bool stream_setup;
@@ -5597,6 +6298,34 @@ void m2ts_rewrite_avc_sample(GF_MediaImporter *import, GF_TSImport *tsimp)
gf_isom_sample_del(&samp);
}
+static void hevc_cfg_add_nalu(GF_HEVCConfig *hevccfg, u8 nal_type, char *data, u32 data_len)
+{
+ u32 i, count;
+ GF_AVCConfigSlot *sl;
+ GF_HEVCParamArray *ar = NULL;
+ count = gf_list_count(hevccfg->param_array);
+ for (i=0; iparam_array, i);
+ if (ar->type == nal_type) break;
+ ar = NULL;
+ }
+ if (!ar) {
+ GF_SAFEALLOC(ar, GF_HEVCParamArray);
+ ar->array_completeness = 1;
+ ar->type = nal_type;
+ ar->nalus = gf_list_new();
+ }
+ GF_SAFEALLOC(sl, GF_AVCConfigSlot);
+ if (data) {
+ sl->data = gf_malloc(sizeof(char)*data_len);
+ sl->size = data_len;
+ memcpy(sl->data, data, data_len);
+ gf_list_add(ar->nalus, ar);
+ } else {
+ ar->array_completeness = 0;
+ }
+}
+
void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
{
GF_Err e;
@@ -5688,6 +6417,13 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
import->nb_tracks++;
tsimp->nb_video++;
break;
+ case GF_M2TS_VIDEO_HEVC:
+ import->tk_info[idx].media_type = GF_4CC('h','e','v','c');
+ import->tk_info[idx].type = GF_ISOM_MEDIA_VISUAL;
+ import->tk_info[idx].lang = pes->lang;
+ import->nb_tracks++;
+ tsimp->nb_video++;
+ break;
case GF_M2TS_AUDIO_MPEG1:
import->tk_info[idx].media_type = GF_4CC('M','P','G','1');
import->tk_info[idx].type = GF_ISOM_MEDIA_AUDIO;
@@ -5813,6 +6549,12 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
oti = GPAC_OTI_VIDEO_AVC;
tsimp->avccfg = gf_odf_avc_cfg_new();
break;
+ case GF_M2TS_VIDEO_HEVC:
+ mtype = GF_ISOM_MEDIA_VISUAL;
+ stype = GF_STREAM_VISUAL;
+ oti = GPAC_OTI_VIDEO_HEVC;
+ tsimp->hevccfg = gf_odf_hevc_cfg_new();
+ break;
case GF_M2TS_AUDIO_MPEG1:
mtype = GF_ISOM_MEDIA_AUDIO;
stype = GF_STREAM_AUDIO;
@@ -5929,7 +6671,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
is_subseq = 1;
case GF_AVC_NALU_SEQ_PARAM:
- idx = AVC_ReadSeqInfo(pck->data+5, pck->data_len-5, &tsimp->avc, is_subseq, NULL);
+ idx = gf_media_avc_read_sps(pck->data+4, pck->data_len-4, &tsimp->avc, is_subseq, NULL);
add_sps = 0;
if (idx>=0) {
@@ -5965,7 +6707,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
}
return;
case GF_AVC_NALU_PIC_PARAM:
- idx = AVC_ReadPictParamSet(pck->data+5, pck->data_len-5, &tsimp->avc);
+ idx = gf_media_avc_read_pps(pck->data+4, pck->data_len-4, &tsimp->avc);
if ((idx>=0) && (tsimp->avc.pps[idx].status==1)) {
tsimp->avc.pps[idx].status = 2;
slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
@@ -5987,9 +6729,96 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
case GF_AVC_NALU_SEI:
break;
if (tsimp->avc.sps_active_idx != -1) {
- idx = AVC_ReformatSEI_NALU(pck->data+4, pck->data_len-4, &tsimp->avc);
+ idx = gf_media_avc_reformat_sei(pck->data+4, pck->data_len-4, &tsimp->avc);
+ if (idx>0) pck->data_len = idx+4;
+ }
+ break;
+ }
+
+ if (tsimp->force_next_au_start) {
+ is_au_start = 1;
+ tsimp->force_next_au_start = 0;
+ }
+ }
+
+ /*avc data for the current sample is stored in annex-B, as we don't know the size of each nal
+ when called back (depending on PES packetization, the end of the nal could be in following pes)*/
+ else if (tsimp->hevccfg && !pck->data[0] && !pck->data[1]) {
+ s32 idx;
+ Bool add_sps, is_subseq = 0;
+ u32 nal_type = (pck->data[4] & 0x7E) >> 1;
+
+ switch (nal_type) {
+ case GF_HEVC_NALU_SEQ_PARAM:
+ idx = gf_media_hevc_read_sps(pck->data+4, pck->data_len-4, &tsimp->hevc);
+ add_sps = 0;
+ if (idx>=0) {
+ if (is_subseq) {
+ if ((tsimp->hevc.sps[idx].state & AVC_SUBSPS_PARSED) && !(tsimp->hevc.sps[idx].state & AVC_SUBSPS_DECLARED)) {
+ tsimp->hevc.sps[idx].state |= AVC_SUBSPS_DECLARED;
+ add_sps = 1;
+ }
+ } else {
+ if ((tsimp->hevc.sps[idx].state & AVC_SPS_PARSED) && !(tsimp->hevc.sps[idx].state & AVC_SPS_DECLARED)) {
+ tsimp->hevc.sps[idx].state |= AVC_SPS_DECLARED;
+ add_sps = 1;
+ }
+ }
+ if (add_sps) {
+ /*always store nalu size on 4 bytes*/
+ tsimp->hevccfg->nal_unit_size = 4;
+ tsimp->hevccfg->configurationVersion = 1;
+
+ tsimp->hevccfg->configurationVersion = 1;
+ tsimp->hevccfg->profile_space = tsimp->hevc.sps[idx].ptl.profile_space;
+ tsimp->hevccfg->profile_idc = tsimp->hevc.sps[idx].ptl.profile_idc;
+ tsimp->hevccfg->constraint_indicator_flags = 0;
+ tsimp->hevccfg->level_idc = tsimp->hevc.sps[idx].ptl.level_idc;
+ tsimp->hevccfg->profile_compatibility_indications = tsimp->hevc.sps[idx].ptl.profile_compatibility_flag;
+ tsimp->hevccfg->chromaFormat = tsimp->hevc.sps[idx].chroma_format_idc;
+ tsimp->hevccfg->luma_bit_depth = tsimp->hevc.sps[idx].bit_depth_luma;
+ tsimp->hevccfg->chroma_bit_depth = tsimp->hevc.sps[idx].bit_depth_chroma;
+
+ hevc_cfg_add_nalu(tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4);
+
+ if (pck->stream->vid_w < tsimp->avc.sps[idx].width)
+ pck->stream->vid_w = tsimp->avc.sps[idx].width;
+ if (pck->stream->vid_h < tsimp->avc.sps[idx].height)
+ pck->stream->vid_h = tsimp->avc.sps[idx].height;
+ }
+ }
+ return;
+ case GF_HEVC_NALU_PIC_PARAM:
+ idx = gf_media_hevc_read_pps(pck->data+4, pck->data_len-4, &tsimp->hevc);
+ if ((idx>=0) && (tsimp->hevc.pps[idx].state==1)) {
+ tsimp->hevc.pps[idx].state = 2;
+ hevc_cfg_add_nalu(tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4);
+ }
+ return;
+ case GF_HEVC_NALU_VID_PARAM:
+ idx = gf_media_hevc_read_vps(pck->data+4, pck->data_len-4, &tsimp->hevc);
+ if ((idx>=0) && (tsimp->hevc.vps[idx].state==1)) {
+ tsimp->hevc.vps[idx].state = 2;
+ tsimp->hevccfg->avgFrameRate = tsimp->hevc.vps[idx].rates[0].avg_pic_rate;
+ tsimp->hevccfg->constantFrameRate = tsimp->hevc.vps[idx].rates[0].constand_pic_rate_idc;
+ tsimp->hevccfg->numTemporalLayers = tsimp->hevc.vps[idx].max_sub_layer;
+ hevc_cfg_add_nalu(tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4);
+ }
+ return;
+ /*remove*/
+ case GF_HEVC_NALU_ACCESS_UNIT:
+ tsimp->force_next_au_start = 1;
+ return;
+ case GF_HEVC_NALU_FILLER_DATA:
+ case GF_HEVC_NALU_END_OF_SEQ:
+ case GF_HEVC_NALU_END_OF_STREAM:
+ return;
+ case GF_HEVC_NALU_SEI_PREFIX:
+/*TODO if (tsimp->avc.sps_active_idx != -1) {
+ idx = gf_media_avc_reformat_sei(pck->data+4, pck->data_len-4, &tsimp->avc);
if (idx>0) pck->data_len = idx+4;
}
+*/
break;
}
@@ -5998,6 +6827,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
tsimp->force_next_au_start = 0;
}
}
+
if (!is_au_start) {
e = gf_isom_append_sample_data(import->dest, tsimp->track, (char*)pck->data, pck->data_len);
if (e) {
@@ -6028,6 +6858,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
case GF_M2TS_VIDEO_MPEG2: gf_import_message(import, GF_OK, "MPEG-2 Video import (TS PID %d)", pck->stream->pid); break;
case GF_M2TS_VIDEO_MPEG4: gf_import_message(import, GF_OK, "MPEG-4 Video import (TS PID %d)", pck->stream->pid); break;
case GF_M2TS_VIDEO_H264: gf_import_message(import, GF_OK, "MPEG-4 AVC/H264 Video import (TS PID %d)", pck->stream->pid); break;
+ case GF_M2TS_VIDEO_HEVC: gf_import_message(import, GF_OK, "MPEG-H HEVC Video import (TS PID %d)", pck->stream->pid); break;
case GF_M2TS_AUDIO_MPEG1: gf_import_message(import, GF_OK, "MPEG-1 Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid); break;
case GF_M2TS_AUDIO_MPEG2: gf_import_message(import, GF_OK, "MPEG-2 Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid); break;
case GF_M2TS_AUDIO_AAC: gf_import_message(import, GF_OK, "MPEG-4 AAC Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid); break;
@@ -7086,7 +7917,11 @@ GF_Err gf_media_import(GF_MediaImporter *importer)
if (!strnicmp(ext, ".h264", 5) || !strnicmp(ext, ".264", 4) || !strnicmp(ext, ".x264", 5)
|| !strnicmp(ext, ".h26L", 5) || !strnicmp(ext, ".26l", 4)
|| !stricmp(fmt, "AVC") || !stricmp(fmt, "H264") )
- return gf_import_h264(importer);
+ return gf_import_avc_h264(importer);
+ /*HEVC video*/
+ if (!strnicmp(ext, ".hevc", 5) || !strnicmp(ext, ".hvc", 4) || !strnicmp(ext, ".265", 4)
+ || !stricmp(fmt, "HEVC") || !stricmp(fmt, "H265") )
+ return gf_import_hevc(importer);
/*AC3*/
if (!strnicmp(ext, ".ac3", 4) || !stricmp(fmt, "AC3") )
return gf_import_ac3(importer);
@@ -7171,6 +8006,8 @@ GF_Err gf_media_change_pl(GF_ISOFile *file, u32 track, u32 profile, u32 level)
switch (stype) {
case GF_ISOM_SUBTYPE_AVC_H264:
case GF_ISOM_SUBTYPE_AVC2_H264:
+ case GF_ISOM_SUBTYPE_AVC3_H264:
+ case GF_ISOM_SUBTYPE_AVC4_H264:
break;
default:
return GF_OK;
diff --git a/src/media_tools/mpd.c b/src/media_tools/mpd.c
index 67727ee..57ae337 100644
--- a/src/media_tools/mpd.c
+++ b/src/media_tools/mpd.c
@@ -311,7 +311,7 @@ static void gf_mpd_parse_segment_base_generic(GF_MPD *mpd, GF_MPD_SegmentBase *s
while ( (att = gf_list_enum(root->attributes, &i)) ) {
if (!strcmp(att->name, "timescale")) seg->timescale = gf_mpd_parse_int(att->value);
else if (!strcmp(att->name, "presentationTimeOffset")) seg->presentation_time_offset = gf_mpd_parse_long_int(att->value);
- else if (!strcmp(att->name, "indexRange")) seg->index_range = gf_mpd_parse_int(att->value);
+ else if (!strcmp(att->name, "indexRange")) seg->index_range = gf_mpd_parse_byte_range(att->value);
else if (!strcmp(att->name, "indexRangeExact")) seg->index_range_exact = gf_mpd_parse_bool(att->value);
}
@@ -784,6 +784,7 @@ void gf_mpd_segment_base_free(void *_item)
GF_MPD_SegmentBase *ptr = (GF_MPD_SegmentBase *)_item;
if (ptr->initialization_segment) gf_mpd_url_free(ptr->initialization_segment);
if (ptr->representation_index) gf_mpd_url_free(ptr->representation_index);
+ if (ptr->index_range) gf_free(ptr->index_range);
gf_free(ptr);
}
@@ -1343,7 +1344,9 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url,
count2 = gf_list_count(prog->bitrates);
for (j = 0; jbitrates, j);
@@ -1365,9 +1368,11 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url,
strncpy(pe->codecs, pe->codecs+1, len-1);
pe->codecs[len-2] = 0;
}
+#ifndef GPAC_DISABLE_MEDIA_IMPORT
if (pe->bandwidth && pe->codecs && pe->width && pe->height) {
import_file = 0;
}
+#endif
/*get rid of level 0 aac*/
elt = gf_list_get(pe->element.playlist.elements, 0);
diff --git a/src/media_tools/mpegts.c b/src/media_tools/mpegts.c
index 2a7b2c2..c401d79 100644
--- a/src/media_tools/mpegts.c
+++ b/src/media_tools/mpegts.c
@@ -62,6 +62,7 @@ const char *gf_m2ts_get_stream_name(u32 streamType)
case GF_M2TS_AUDIO_AAC: return "AAC Audio";
case GF_M2TS_VIDEO_MPEG4: return "MPEG-4 Video";
case GF_M2TS_VIDEO_H264: return "MPEG-4/H264 Video";
+ case GF_M2TS_VIDEO_HEVC: return "MPEG-H HEVC Video";
case GF_M2TS_AUDIO_AC3: return "Dolby AC3 Audio";
case GF_M2TS_AUDIO_DTS: return "Dolby DTS Audio";
@@ -109,7 +110,7 @@ static u32 gf_m2ts_reframe_reset(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool sam
return 0;
}
-static u32 gf_m2ts_reframe_avc_h264(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len)
+static u32 gf_m2ts_reframe_nalu_video(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, Bool is_hevc)
{
Bool au_start_in_pes=0;
Bool prev_is_au_delim=0;
@@ -186,47 +187,94 @@ static u32 gf_m2ts_reframe_avc_h264(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool
}
start_code_found = short_start_code ? 2 : 1;
- nal_type = pck.data[4] & 0x1F;
+ if (is_hevc) {
+ nal_type = (pck.data[4] & 0x7E) >> 1;
- /*check for SPS and update stream info*/
+ /*check for SPS and update stream info*/
#ifndef GPAC_DISABLE_AV_PARSERS
- if (!pes->vid_w && (nal_type==GF_AVC_NALU_SEQ_PARAM)) {
- AVCState avc;
- s32 idx;
- memset(&avc, 0, sizeof(AVCState));
- avc.sps_active_idx = -1;
- idx = AVC_ReadSeqInfo(data+5, sc_pos-5, &avc, 0, NULL);
-
- if (idx>=0) {
- pes->vid_w = avc.sps[idx].width;
- pes->vid_h = avc.sps[idx].height;
+ if (!pes->vid_w && (nal_type==GF_HEVC_NALU_SEQ_PARAM)) {
+ HEVCState hevc;
+ s32 idx;
+ memset(&hevc, 0, sizeof(HEVCState));
+ hevc.sps_active_idx = -1;
+ idx = gf_media_hevc_read_sps(data+4, sc_pos-4, &hevc);
+
+ if (idx>=0) {
+ pes->vid_w = hevc.sps[idx].width;
+ pes->vid_h = hevc.sps[idx].height;
+ }
}
- }
#endif
- /*check AU start type*/
- if (nal_type==GF_AVC_NALU_ACCESS_UNIT) {
- if (!prev_is_au_delim) {
- if (au_start_in_pes) {
- /*FIXME - we should check the AVC framerate to update the timing ...*/
- pck.DTS += 3000;
- pck.PTS += 3000;
-// GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID%d: Two AVC AUs start in this PES packet - cannot recompute non-first AU timing\n", pes->pid));
+ /*check AU start type*/
+ if (nal_type==GF_HEVC_NALU_ACCESS_UNIT) {
+ if (!prev_is_au_delim) {
+ if (au_start_in_pes) {
+ /*FIXME - we should check the AVC framerate to update the timing ...*/
+ pck.DTS += 3000;
+ pck.PTS += 3000;
+ // GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID%d: Two AVC AUs start in this PES packet - cannot recompute non-first AU timing\n", pes->pid));
+ }
+ pck.flags = GF_M2TS_PES_PCK_AU_START;
+ force_new_au = 0;
+ au_start_in_pes = 1;
+ ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
+ prev_is_au_delim=1;
}
- pck.flags = GF_M2TS_PES_PCK_AU_START;
- force_new_au = 0;
- au_start_in_pes = 1;
+ } else if ((nal_type==GF_HEVC_NALU_SLICE_IDR_W_DLP)
+ || (nal_type==GF_HEVC_NALU_SLICE_IDR_N_LP)
+ ) {
+ pck.flags = GF_M2TS_PES_PCK_RAP;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
- prev_is_au_delim=1;
+ prev_is_au_delim=0;
+ }
+ else {
+ pck.flags = 0;
+ ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
+ prev_is_au_delim=0;
+ }
+ } else {
+ nal_type = pck.data[4] & 0x1F;
+
+ /*check for SPS and update stream info*/
+#ifndef GPAC_DISABLE_AV_PARSERS
+ if (!pes->vid_w && (nal_type==GF_AVC_NALU_SEQ_PARAM)) {
+ AVCState avc;
+ s32 idx;
+ memset(&avc, 0, sizeof(AVCState));
+ avc.sps_active_idx = -1;
+ idx = gf_media_avc_read_sps(data+4, sc_pos-4, &avc, 0, NULL);
+
+ if (idx>=0) {
+ pes->vid_w = avc.sps[idx].width;
+ pes->vid_h = avc.sps[idx].height;
+ }
+ }
+#endif
+ /*check AU start type*/
+ if (nal_type==GF_AVC_NALU_ACCESS_UNIT) {
+ if (!prev_is_au_delim) {
+ if (au_start_in_pes) {
+ /*FIXME - we should check the AVC framerate to update the timing ...*/
+ pck.DTS += 3000;
+ pck.PTS += 3000;
+ // GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID%d: Two AVC AUs start in this PES packet - cannot recompute non-first AU timing\n", pes->pid));
+ }
+ pck.flags = GF_M2TS_PES_PCK_AU_START;
+ force_new_au = 0;
+ au_start_in_pes = 1;
+ ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
+ prev_is_au_delim=1;
+ }
+ } else if (nal_type==GF_AVC_NALU_IDR_SLICE) {
+ pck.flags = GF_M2TS_PES_PCK_RAP;
+ ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
+ prev_is_au_delim=0;
+ }
+ else {
+ pck.flags = 0;
+ ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
+ prev_is_au_delim=0;
}
- } else if (nal_type==GF_AVC_NALU_IDR_SLICE) {
- pck.flags = GF_M2TS_PES_PCK_RAP;
- ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
- prev_is_au_delim=0;
- }
- else {
- pck.flags = 0;
- ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
- prev_is_au_delim=0;
}
data += sc_pos;
@@ -243,8 +291,10 @@ static u32 gf_m2ts_reframe_avc_h264(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool
}
/*we did not consume all data*/
if (!start_code_found) {
+ u32 min_size = is_hevc ? 6 : 5;
/*if not enough data to locate start code, store it*/
- if (data_len<5) return data_len;
+ if (data_len < min_size )
+ return data_len;
/*otherwise this is the middle of a frame, let's dispatch it*/
}
@@ -275,6 +325,16 @@ static u32 gf_m2ts_reframe_avc_h264(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool
return 0;
}
+static u32 gf_m2ts_reframe_avc_h264(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len)
+{
+ return gf_m2ts_reframe_nalu_video(ts, pes, same_pts, data, data_len, 0);
+}
+
+static u32 gf_m2ts_reframe_hevc(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len)
+{
+ return gf_m2ts_reframe_nalu_video(ts, pes, same_pts, data, data_len, 1);
+}
+
static u32 gf_m2ts_reframe_mpeg_video(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len)
{
u32 sc_pos = 0;
@@ -1533,6 +1593,7 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF
case GF_M2TS_VIDEO_MPEG4:
case GF_M2TS_SYSTEMS_MPEG4_PES:
case GF_M2TS_VIDEO_H264:
+ case GF_M2TS_VIDEO_HEVC:
case GF_M2TS_AUDIO_AC3:
case GF_M2TS_AUDIO_DTS:
case GF_M2TS_SUBTITLE_DVB:
@@ -2478,6 +2539,9 @@ GF_Err gf_m2ts_set_pes_framing(GF_M2TS_PES *pes, u32 mode)
case GF_M2TS_VIDEO_H264:
pes->reframe = gf_m2ts_reframe_avc_h264;
break;
+ case GF_M2TS_VIDEO_HEVC:
+ pes->reframe = gf_m2ts_reframe_hevc;
+ break;
case GF_M2TS_AUDIO_AAC:
pes->reframe = gf_m2ts_reframe_aac_adts;
break;
@@ -2686,8 +2750,9 @@ static u32 TSDemux_DemuxRun(void *_p)
gf_dm_sess_process(ts->dnload);
gf_sleep(1);
}
- } else if (ts->file) {
+ } else if (ts->file || ts->ts_data_chunk) {
u32 pos = 0;
+ GF_BitStream *ts_bs = NULL;
if (ts->segment_switch) {
ts->segment_switch = 0;
@@ -2703,19 +2768,23 @@ static u32 TSDemux_DemuxRun(void *_p)
pos = 0;
}
}
- gf_f64_seek(ts->file, pos, SEEK_SET);
-restart_file:
- gf_f64_seek(ts->file, ts->start_byterange, SEEK_SET);
+restart_stream:
+
+ if (ts->file)
+ ts_bs = gf_bs_from_file(ts->file, GF_BITSTREAM_READ);
+ else
+ ts_bs = gf_bs_new(ts->ts_data_chunk, ts->ts_data_chunk_size, GF_BITSTREAM_READ);
+
+ gf_bs_seek(ts_bs, ts->start_byterange);
- while (ts->run_state && !feof(ts->file)) {
+ while (ts->run_state && gf_bs_available(ts_bs)) {
/*m2ts chunks by chunks*/
- size = fread(data, 1, 188, ts->file);
+ size = gf_bs_read_data(ts_bs, data, 188);
if (!size && (ts->loop_demux == 1)) {
- gf_f64_seek(ts->file, pos, SEEK_SET);
+ gf_bs_seek(ts_bs, pos);
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TSDemux] Loop \n"));
- gf_sleep(500);
- size = fread(data, 1, 188, ts->file);
+ size = gf_bs_read_data(ts_bs, data, 188);
}
if (!size) break;
if (size != 188) {
@@ -2725,9 +2794,7 @@ restart_file:
gf_m2ts_process_data(ts, data, size);
ts->nb_pck++;
- //fprintf(stderr, "TS packet #%d\r", ts->nb_pck);
-
- if (ts->end_byterange && (gf_f64_tell(ts->file)>=ts->end_byterange))
+ if (ts->end_byterange && (gf_bs_get_position(ts_bs) >= ts->end_byterange))
break;
//gf_sleep(0);
@@ -2737,13 +2804,13 @@ restart_file:
continue;
}
- if(feof(ts->file) && ts->loop_demux == 1){
- gf_f64_seek(ts->file, pos, SEEK_SET);
+ if (!gf_bs_available(ts_bs) && ts->loop_demux == 1){
+ gf_bs_seek(ts_bs, pos);
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TSDemux] Loop \n"));
gf_sleep(3000);
}
}
- if (feof(ts->file)) {
+ if (!gf_bs_available(ts_bs)) {
u32 i;
for (i=0; iess[i]) {
@@ -2757,16 +2824,30 @@ restart_file:
}
next_segment_setup:
+ gf_bs_del(ts_bs);
+ ts_bs = NULL;
if (ts->run_state && ts->query_next) {
const char *next_url = NULL;
ts->query_next(ts->query_udta, 0, &next_url, &ts->start_byterange, &ts->end_byterange);
if (next_url) {
- fclose(ts->file);
- ts->file = gf_f64_open(next_url, "rb");
gf_m2ts_set_segment_switch(ts);
- if (ts->file) goto restart_file;
- GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDemux] Cannot open next file %s\n", next_url));
+ if (!strncmp(next_url, "gmem://", 7)) {
+ u32 size;
+ void *mem_address;
+ if (sscanf(next_url, "gmem://%d@%p", &size, &mem_address) != 2) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDemux] Cannot open next file %s\n", next_url));
+ } else {
+ ts->ts_data_chunk_size = size;
+ ts->ts_data_chunk = mem_address;
+ if (ts->ts_data_chunk_size) goto restart_stream;
+ }
+ } else {
+ if (ts->file) fclose(ts->file);
+ ts->file = gf_f64_open(next_url, "rb");
+ if (ts->file) goto restart_stream;
+ GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDemux] Cannot open next file %s\n", next_url));
+ }
}
}
}
@@ -3052,16 +3133,28 @@ static GF_Err TSDemux_SetupFile(GF_M2TS_Demuxer *ts, char *url)
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[TSDemux] TS file already being processed: %s\n", url));
return GF_IO_ERR;
}
-
- ts->file = gf_f64_open(url, "rb");
- if (!ts->file) {
- GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[TSDemux] Could not open TS file: %s\n", url));
- return GF_IO_ERR;
- }
strcpy(ts->filename, url);
- gf_f64_seek(ts->file, 0, SEEK_END);
- ts->file_size = gf_f64_tell(ts->file);
+ if (!strncmp(url, "gmem://", 7)) {
+ u32 size;
+ void *mem_address;
+ if (sscanf(url, "gmem://%d@%p", &size, &mem_address) != 2)
+ return GF_IO_ERR;
+ ts->ts_data_chunk_size = size;
+ ts->ts_data_chunk = mem_address;
+ } else {
+
+ ts->file = gf_f64_open(url, "rb");
+ if (!ts->file) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[TSDemux] Could not open TS file: %s\n", url));
+ return GF_IO_ERR;
+ }
+ strcpy(ts->filename, url);
+
+ gf_f64_seek(ts->file, 0, SEEK_END);
+ ts->file_size = gf_f64_tell(ts->file);
+
+ }
/* reinitialization for seek */
ts->end_range = ts->start_range = 0;
@@ -3131,6 +3224,7 @@ GF_Err TSDemux_CloseDemux(GF_M2TS_Demuxer *ts)
if (ts->file) fclose(ts->file);
ts->file = NULL;
+ ts->ts_data_chunk = NULL;
return GF_OK;
}
@@ -3155,7 +3249,25 @@ Bool gf_m2ts_probe_file(const char *fileName)
{
char buf[188];
u32 count = 10;
- FILE *t = gf_f64_open(fileName, "rb");
+ FILE *t;
+
+ if (!strncmp(fileName, "gmem://", 7)) {
+ u32 size;
+ u8 *mem_address;
+ if (sscanf(fileName, "gmem://%d@%p", &size, &mem_address) != 2) {
+ return GF_URL_ERROR;
+ }
+ while (size>188 && count) {
+ if (mem_address[0] != 0x47)
+ return 0;
+ mem_address+=188;
+ size-=188;
+ count--;
+ }
+ return 1;
+ }
+
+ t = gf_f64_open(fileName, "rb");
while (t && count) {
u32 read = fread(buf, 1, 188, t);
if (!read) {
@@ -3175,13 +3287,13 @@ Bool gf_m2ts_probe_file(const char *fileName)
static void rewrite_pts_dts(unsigned char *ptr, u64 TS)
{
ptr[0] &= 0xf1;
- ptr[0] |= (unsigned char)((TS&0x1c0000000)>>29);
- ptr[1] = (unsigned char)((TS&0x03fc00000)>>22);
+ ptr[0] |= (unsigned char)((TS&0x1c0000000ULL)>>29);
+ ptr[1] = (unsigned char)((TS&0x03fc00000ULL)>>22);
ptr[2] &= 0x1;
- ptr[2] |= (unsigned char)((TS&0x0003f8000)>>14);
- ptr[3] = (unsigned char)((TS&0x000007f80)>>7);
+ ptr[2] |= (unsigned char)((TS&0x0003f8000ULL)>>14);
+ ptr[3] = (unsigned char)((TS&0x000007f80ULL)>>7);
ptr[4] &= 0x1;
- ptr[4] |= (unsigned char)((TS&0x00000007f)<<1);
+ ptr[4] |= (unsigned char)((TS&0x00000007fULL)<<1);
assert(((u64)(ptr[0]&0xe)<<29) + ((u64)ptr[1]<<22) + ((u64)(ptr[2]&0xfe)<<14) + ((u64)ptr[3]<<7) + ((ptr[4]&0xfe)>>1) == TS);
}
@@ -3235,13 +3347,13 @@ GF_Err gf_m2ts_restamp(char *buffer, u32 size, s64 ts_shift, u8 *is_pes)
}
pck[11] = (unsigned char)(0xff&pcr_ext);
}
+ /*add adaptation_field_length field*/
+ adaptation_field_length++;
}
if (!is_pes[pid] || !(pck[1]&0x40)) {
done+=188;
continue;
}
- if (adaptation_field_length)
- adaptation_field_length++; /*add adaptation_field_length field*/
pesh = &pck[4+adaptation_field_length];
diff --git a/src/media_tools/text_import.c b/src/media_tools/text_import.c
index 8b4e181..3feedfb 100644
--- a/src/media_tools/text_import.c
+++ b/src/media_tools/text_import.c
@@ -1960,7 +1960,10 @@ GF_Err gf_import_timed_text(GF_MediaImporter *import)
u32 fmt;
e = gf_text_guess_format(import->in_name, &fmt);
if (e) return e;
- if (!fmt) return GF_NOT_SUPPORTED;
+ if (!fmt) {
+ GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[TTXT Import] Input %s does not look like a supported text format - ignoring\n", import->in_name));
+ return GF_NOT_SUPPORTED;
+ }
if (import->flags & GF_IMPORT_PROBE_ONLY) {
if (fmt==GF_TEXT_IMPORT_SUB) import->flags |= GF_IMPORT_OVERRIDE_FPS;
return GF_OK;
diff --git a/src/odf/descriptors.c b/src/odf/descriptors.c
index ea42ff4..70d668e 100644
--- a/src/odf/descriptors.c
+++ b/src/odf/descriptors.c
@@ -791,6 +791,154 @@ exit:
return e;
}
+
+
+GF_EXPORT
+GF_HEVCConfig *gf_odf_hevc_cfg_new()
+{
+ GF_HEVCConfig *cfg;
+ GF_SAFEALLOC(cfg, GF_HEVCConfig);
+ if (!cfg) return NULL;
+ cfg->param_array = gf_list_new();
+ cfg->nal_unit_size = 4;
+ return cfg;
+}
+
+GF_EXPORT
+void gf_odf_hevc_cfg_del(GF_HEVCConfig *cfg)
+{
+ if (!cfg) return;
+ while (gf_list_count(cfg->param_array)) {
+ GF_HEVCParamArray *pa = (GF_HEVCParamArray*)gf_list_get(cfg->param_array, 0);
+ gf_list_rem(cfg->param_array, 0);
+
+ while (gf_list_count(pa->nalus)) {
+ GF_AVCConfigSlot *n = (GF_AVCConfigSlot*)gf_list_get(pa->nalus, 0);
+ gf_list_rem(pa->nalus, 0);
+ if (n->data) gf_free(n->data);
+ gf_free(n);
+ }
+ gf_free(pa);
+ }
+ gf_free(cfg);
+}
+
+GF_EXPORT
+GF_Err gf_odf_hevc_cfg_write_bs(GF_HEVCConfig *cfg, GF_BitStream *bs)
+{
+ u32 i, count;
+
+ gf_bs_write_int(bs, cfg->configurationVersion, 8);
+ gf_bs_write_int(bs, cfg->profile_space, 3);
+ gf_bs_write_int(bs, cfg->profile_idc, 5);
+ gf_bs_write_int(bs, cfg->constraint_indicator_flags, 16);
+ gf_bs_write_int(bs, cfg->level_idc, 8);
+ gf_bs_write_int(bs, cfg->profile_compatibility_indications, 32);
+ gf_bs_write_int(bs, 0xFF, 6);
+ gf_bs_write_int(bs, cfg->chromaFormat, 2);
+ gf_bs_write_int(bs, 0xFF, 5);
+ gf_bs_write_int(bs, cfg->luma_bit_depth-8, 3);
+ gf_bs_write_int(bs, 0xFF, 5);
+ gf_bs_write_int(bs, cfg->chroma_bit_depth-8, 3);
+ gf_bs_write_int(bs, cfg->avgFrameRate, 16);
+ gf_bs_write_int(bs, cfg->constantFrameRate, 2);
+ gf_bs_write_int(bs, cfg->numTemporalLayers, 3);
+ gf_bs_write_int(bs, 1, 1);
+ gf_bs_write_int(bs, cfg->nal_unit_size - 1, 2);
+
+ count = gf_list_count(cfg->param_array);
+ gf_bs_write_int(bs, count, 8);
+ for (i=0; iparam_array, i);
+ gf_bs_write_int(bs, ar->array_completeness, 1);
+ gf_bs_write_int(bs, 0, 1);
+ gf_bs_write_int(bs, ar->type, 6);
+ nalucount = gf_list_count(ar->nalus);
+ gf_bs_write_int(bs, nalucount, 16);
+ for (j=0; jnalus, j);
+ gf_bs_write_int(bs, sl->size, 16);
+ gf_bs_write_data(bs, sl->data, sl->size);
+ }
+ }
+ return GF_OK;
+}
+
+GF_EXPORT
+GF_Err gf_odf_hevc_cfg_write(GF_HEVCConfig *cfg, char **outData, u32 *outSize)
+{
+ GF_Err e;
+ GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
+ *outSize = 0;
+ *outData = NULL;
+ e = gf_odf_hevc_cfg_write_bs(cfg, bs);
+ if (e==GF_OK)
+ gf_bs_get_content(bs, outData, outSize);
+
+ gf_bs_del(bs);
+ return e;
+}
+
+GF_EXPORT
+GF_HEVCConfig *gf_odf_hevc_cfg_read_bs(GF_BitStream *bs)
+{
+ u32 i, count;
+ GF_HEVCConfig *cfg = gf_odf_hevc_cfg_new();
+
+ cfg->configurationVersion = gf_bs_read_int(bs, 8);
+ cfg->profile_space = gf_bs_read_int(bs, 3);
+ cfg->profile_idc = gf_bs_read_int(bs, 5);
+ cfg->constraint_indicator_flags = gf_bs_read_int(bs, 16);
+ cfg->level_idc = gf_bs_read_int(bs, 8);
+ cfg->profile_compatibility_indications = gf_bs_read_int(bs, 32);
+ gf_bs_read_int(bs, 6);
+ cfg->chromaFormat = gf_bs_read_int(bs, 2);
+ gf_bs_read_int(bs, 5);
+ cfg->luma_bit_depth = 8 + gf_bs_read_int(bs, 3);
+ gf_bs_read_int(bs, 5);
+ cfg->chroma_bit_depth = 8 + gf_bs_read_int(bs, 3);
+ cfg->avgFrameRate = gf_bs_read_int(bs, 16);
+ cfg->constantFrameRate = gf_bs_read_int(bs, 2);
+ cfg->numTemporalLayers = gf_bs_read_int(bs, 3);
+ gf_bs_read_int(bs, 1);
+ cfg->nal_unit_size = 1 + gf_bs_read_int(bs, 2);
+
+ count = gf_bs_read_int(bs, 8);
+ for (i=0; inalus = gf_list_new();
+ gf_list_add(cfg->param_array, ar);
+
+ ar->array_completeness = gf_bs_read_int(bs, 1);
+ gf_bs_read_int(bs, 1);
+ ar->type = gf_bs_read_int(bs, 6);
+ nalucount = gf_bs_read_int(bs, 16);
+ for (j=0; jsize = gf_bs_read_int(bs, 16);
+
+ sl->data = (char *)gf_malloc(sizeof(char) * sl->size);
+ gf_bs_read_data(bs, sl->data, sl->size);
+ gf_list_add(ar->nalus, sl);
+ }
+ }
+ return cfg;
+}
+
+GF_EXPORT
+GF_HEVCConfig *gf_odf_hevc_cfg_read(char *dsi, u32 dsi_size)
+{
+ GF_BitStream *bs = gf_bs_new(dsi, dsi_size, GF_BITSTREAM_READ);
+ GF_HEVCConfig *cfg = gf_odf_hevc_cfg_read_bs(bs);
+ gf_bs_del(bs);
+ return cfg;
+}
+
GF_EXPORT
const char *gf_afx_get_type_description(u8 afx_code)
{
diff --git a/src/scene_manager/loader_bt.c b/src/scene_manager/loader_bt.c
index 5ceeb21..40a9038 100644
--- a/src/scene_manager/loader_bt.c
+++ b/src/scene_manager/loader_bt.c
@@ -34,7 +34,7 @@
#include
-#ifndef GPAC_DISABLE_LOADER_BT
+#if !defined(GPAC_DISABLE_LOADER_BT) && !defined(GPAC_DISABLE_ZLIB)
#include
@@ -1094,23 +1094,31 @@ u32 gf_bt_get_next_proto_id(GF_BTParser *parser)
u32 gf_bt_get_def_id(GF_BTParser *parser, char *defName)
{
- GF_Node *n;
- u32 ID;
+ GF_Node *n=NULL;
+ u32 ID=0;
if (sscanf(defName, "N%u", &ID) == 1) {
- ID ++;
- n = gf_sg_find_node(parser->load->scene_graph, ID);
- /*if an existing node use*/
- if (n) {
- u32 id;
- u32 nID = gf_bt_get_next_node_id(parser);
- const char *name = gf_node_get_name_and_id(n, &id);
- gf_bt_report(parser, GF_OK, "changing node \"%s\" Binary ID from %d to %d", name, id -1, nID-1);
- gf_node_set_id(n, nID, name);
+ u32 k=1;
+ while (defName[k]) {
+ if (strchr("0123456789", defName[k])==0) {
+ ID = 0;
+ break;
+ }
+ k++;
}
- if (parser->load->ctx && (parser->load->ctx->max_node_idload->ctx->max_node_id=ID;
- } else {
- ID = gf_bt_get_next_node_id(parser);
- }
+ if (ID) {
+ ID ++;
+ n = gf_sg_find_node(parser->load->scene_graph, ID);
+ if (!n) {
+ if (parser->load->ctx && (parser->load->ctx->max_node_idload->ctx->max_node_id=ID;
+ return ID;
+ }
+ }
+ }
+
+ ID = gf_bt_get_next_node_id(parser);
+ if (n) {
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[BT Parsing] (line %d) Binary ID %d already assigned to %s - keeping internal ID %d", parser->line, gf_node_get_name(n), ID));
+ }
return ID;
}
diff --git a/src/scene_manager/loader_xmt.c b/src/scene_manager/loader_xmt.c
index a617c83..a7b85fa 100644
--- a/src/scene_manager/loader_xmt.c
+++ b/src/scene_manager/loader_xmt.c
@@ -607,19 +607,29 @@ static u32 xmt_get_next_node_id(GF_XMTParser *parser)
}
static u32 xmt_get_node_id(GF_XMTParser *parser, char *name)
{
- GF_Node *n;
- u32 ID;
+ GF_Node *n = NULL;
+ u32 ID = 0;
if (sscanf(name, "N%u", &ID) == 1) {
- ID ++;
- n = gf_sg_find_node(parser->load->scene_graph, ID);
- if (n) {
- u32 nID = xmt_get_next_node_id(parser);
- xmt_report(parser, GF_OK, "WARNING: changing node \"%s\" ID from %d to %d", gf_node_get_name(n), gf_node_get_id(n)-1, nID-1);
- gf_node_set_id(n, nID, gf_node_get_name(n));
- }
- if (parser->load->ctx && (parser->load->ctx->max_node_idload->ctx->max_node_id=ID;
- } else {
- ID = xmt_get_next_node_id(parser);
+ u32 k=1;
+ while (name[k]) {
+ if (strchr("0123456789", name[k])==0) {
+ ID = 0;
+ break;
+ }
+ k++;
+ }
+ if (ID) {
+ ID ++;
+ n = gf_sg_find_node(parser->load->scene_graph, ID);
+ if (!n) {
+ if (parser->load->ctx && (parser->load->ctx->max_node_idload->ctx->max_node_id=ID;
+ return ID;
+ }
+ }
+ }
+ ID = xmt_get_next_node_id(parser);
+ if (n) {
+ GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[XMT Parsing] (line %d) Binary ID %s already assigned to %s - keeping internal ID %d\n", gf_xml_sax_get_line(parser->sax_parser), name, gf_node_get_name(n), ID));
}
return ID;
}
diff --git a/src/scene_manager/scene_engine.c b/src/scene_manager/scene_engine.c
index e2254fb..9afe84e 100644
--- a/src/scene_manager/scene_engine.c
+++ b/src/scene_manager/scene_engine.c
@@ -417,10 +417,16 @@ start:
assert(fsize < 1<<31);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[SceneEngine] Sending DIMS data - sizes: raw (%d)", buffer_len));
if (compress_dims) {
+#ifndef GPAC_DISABLE_ZLIB
dims_header |= GF_DIMS_UNIT_C;
e = gf_gz_compress_payload(&buffer, buffer_len, &buffer_len);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("/ compressed (%d)", buffer_len));
if (e) goto exit;
+#else
+ GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: your version of GPAC was compile with no libz support. Abort."));
+ e = GF_NOT_SUPPORTED;
+ goto exit;
+#endif
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("\n"));
diff --git a/src/scene_manager/swf_parse.c b/src/scene_manager/swf_parse.c
index 1b5b39b..46307e9 100644
--- a/src/scene_manager/swf_parse.c
+++ b/src/scene_manager/swf_parse.c
@@ -28,10 +28,10 @@
#include
#include
-#include
+#if !defined(GPAC_DISABLE_SWF_IMPORT) && !defined(GPAC_DISABLE_ZLIB)
-#ifndef GPAC_DISABLE_SWF_IMPORT
+#include
enum
{
diff --git a/src/scenegraph/dom_smjs.c b/src/scenegraph/dom_smjs.c
index 7b1cc04..bf7cb49 100644
--- a/src/scenegraph/dom_smjs.c
+++ b/src/scenegraph/dom_smjs.c
@@ -472,7 +472,7 @@ static SMJS_FUNC_PROP_GET( dom_nodelist_getProperty)
}
return JS_TRUE;
}
-static SMJS_FUNC_PROP_SET( dom_nodelist_setProperty)
+static SMJS_FUNC_PROP_SET_NOVP( dom_nodelist_setProperty)
/*avoids gcc warning*/
if (!obj) obj=NULL;
@@ -1405,7 +1405,7 @@ static SMJS_FUNC_PROP_GET( dom_document_getProperty )
return JS_TRUE;
}
-static SMJS_FUNC_PROP_SET(dom_document_setProperty)
+static SMJS_FUNC_PROP_SET_NOVP(dom_document_setProperty)
u32 prop_id;
GF_SceneGraph *sg = dom_get_doc(c, obj);
@@ -3445,10 +3445,11 @@ static SMJS_FUNC_PROP_GET( storage_getProperty)
/*avoids gcc warning*/
if (!id) id=0;
if (!GF_JS_InstanceOf(c, obj, &dom_rt->storageClass, NULL) ) return JS_TRUE;
+ *vp = JSVAL_VOID;
return JS_TRUE;
}
-static SMJS_FUNC_PROP_SET( storage_setProperty)
+static SMJS_FUNC_PROP_SET_NOVP( storage_setProperty)
/*avoids gcc warning*/
if (!id) id=0;
@@ -3526,29 +3527,29 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global)
SMJS_FUNCTION_SPEC(0, 0, 0)
};
JSPropertySpec nodeProps[] = {
- {"nodeName", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"nodeValue", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"nodeType", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"parentNode", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"childNodes", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"firstChild", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"lastChild", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"previousSibling", 7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"nextSibling", 8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"attributes", 9, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"ownerDocument", 10, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"namespaceURI", 11, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"prefix", 12, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"localName", 13, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"baseURI", 14, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"textContent", 15, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
+ SMJS_PROPERTY_SPEC("nodeName", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("nodeValue", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("nodeType", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("parentNode", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("childNodes", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("firstChild", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("lastChild", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("previousSibling", 7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("nextSibling", 8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("attributes", 9, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("ownerDocument", 10, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("namespaceURI", 11, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("prefix", 12, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("localName", 13, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("baseURI", 14, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("textContent", 15, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
/*elementTraversal interface*/
- {"firstElementChild", 16, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"lastElementChild", 17, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"previousElementSibling", 18, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"nextElementSibling", 19, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("firstElementChild", 16, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("lastElementChild", 17, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("previousElementSibling", 18, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("nextElementSibling", 19, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
GF_JS_InitClass(c, global, 0, &dom_rt->domNodeClass, 0, 0, nodeProps, nodeFuncs, 0, 0);
if (!dom_rt->domNodeClass._proto) {
@@ -3590,17 +3591,17 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global)
};
JSPropertySpec documentProps[] = {
- {"doctype", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"implementation", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"documentElement", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"inputEncoding", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"xmlEncoding", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"xmlStandalone", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"xmlVersion", 7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"strictErrorChecking", 8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"documentURI", 9, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"domConfig", 10, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0},
+ SMJS_PROPERTY_SPEC("doctype", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("implementation", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("documentElement", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("inputEncoding", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("xmlEncoding", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("xmlStandalone", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("xmlVersion", 7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("strictErrorChecking", 8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("documentURI", 9, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("domConfig", 10, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0),
};
GF_JS_InitClass(c, global, dom_rt->domNodeClass._proto, &dom_rt->domDocumentClass, 0, 0, documentProps, documentFuncs, 0, 0);
@@ -3633,9 +3634,9 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global)
};
JSPropertySpec elementProps[] = {
- {"tagName", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"schemaTypeInfo", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0},
+ SMJS_PROPERTY_SPEC("tagName", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("schemaTypeInfo", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0),
};
GF_JS_InitClass(c, global, dom_rt->domNodeClass._proto, &dom_rt->domElementClass, 0, 0, elementProps, elementFuncs, 0, 0);
GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[DOMCore] element class initialized\n"));
@@ -3656,12 +3657,12 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global)
SMJS_FUNCTION_SPEC(0, 0, 0)
};
JSPropertySpec textProps[] = {
- {"data", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"length", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("data", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("length", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*text*/
- {"isElementContentWhitespace", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"wholeText", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0},
+ SMJS_PROPERTY_SPEC("isElementContentWhitespace", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("wholeText", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0),
};
GF_JS_InitClass(c, global, dom_rt->domNodeClass._proto, &dom_rt->domTextClass, 0, 0, textProps, textFuncs, 0, 0);
GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[DOMCore] text class initialized\n"));
@@ -3680,59 +3681,58 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global)
SMJS_FUNCTION_SPEC(0, 0, 0)
};
JSPropertySpec eventProps[] = {
- {"type", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"target", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"currentTarget", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"eventPhase", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"bubbles", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"cancelable", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"timeStamp", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"namespaceURI", 7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"defaultPrevented", 8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("type", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("target", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("currentTarget", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("eventPhase", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("bubbles", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("cancelable", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("timeStamp", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("namespaceURI", 7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("defaultPrevented", 8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*UIEvent*/
- {"detail", 20, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("detail", 20, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*text, connectionEvent*/
- {"data", 25, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("data", 25, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*MouseEvent*/
- {"screenX", 30, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"screenY", 31, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"clientX", 32, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"clientY", 33, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"button", 34, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"relatedTarget", 35, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("screenX", 30, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("screenY", 31, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("clientX", 32, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("clientY", 33, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("button", 34, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("relatedTarget", 35, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*wheelEvent*/
- {"wheelDelta", 36, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("wheelDelta", 36, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*keyboard*/
- {"keyIdentifier", 40, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"keyChar", 41, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"charCode", 42, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("keyIdentifier", 40, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("keyChar", 41, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("charCode", 42, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*progress*/
- {"lengthComputable",50, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"typeArg", 51, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"loaded", 52, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"total", 53, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"bufferLevelValid", 54, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"bufferLevel", 55, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"bufferRemainingTime", 56, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"status", 57, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("lengthComputable",50, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("typeArg", 51, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("loaded", 52, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("total", 53, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("bufferLevelValid", 54, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("bufferLevel", 55, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("bufferRemainingTime", 56, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("status", 57, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*used by vrml*/
- {"width", 60, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"height", 61, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"offset_x", 62, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"offset_y", 63, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"vp_width", 64, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"vp_height", 65, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"translation_x", 66, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"translation_y", 67, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"type3d", 68, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"error", 69, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
-
-
- {0, 0, 0, 0, 0},
+ SMJS_PROPERTY_SPEC("width", 60, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("height", 61, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("offset_x", 62, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("offset_y", 63, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("vp_width", 64, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("vp_height", 65, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("translation_x", 66, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("translation_y", 67, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("type3d", 68, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("error", 69, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0),
};
GF_JS_InitClass(c, global, 0, &dom_rt->domEventClass, 0, 0, eventProps, eventFuncs, 0, 0);
GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[DOMCore] Event class initialized\n"));
@@ -3754,8 +3754,8 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global)
SMJS_FUNCTION_SPEC(0, 0, 0)
};
JSPropertySpec nodeListProps[] = {
- {"length", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("length", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
GF_JS_InitClass(c, global, 0, &dom_rt->domNodeListClass, 0, 0, nodeListProps, nodeListFuncs, 0, 0);
GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[DOMCore] nodeList class initialized\n"));
@@ -3763,13 +3763,13 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global)
{
JSPropertySpec xmlHTTPRequestClassProps[] = {
- {"onreadystatechange", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"readyState", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"responseText", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"responseXML", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"status", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"statusText", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("onreadystatechange", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("readyState", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("responseText", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("responseXML", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("status", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("statusText", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec xmlHTTPRequestClassFuncs[] = {
SMJS_FUNCTION_SPEC("open", xml_http_open, 2),
@@ -3787,7 +3787,7 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global)
{
JSPropertySpec storageClassProps[] = {
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec storageClassFuncs[] = {
SMJS_FUNCTION_SPEC(0, 0, 0)
@@ -3810,14 +3810,14 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global)
if (dcci && dcci->RootNode) {
JSPropertySpec DCCIClassProps[] = {
- {"value", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"valueType", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"propertyType", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"readOnly", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"DCCIMetadataInterfaceType", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"DCCIMetadataInterface", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"version", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("value", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("valueType", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("propertyType", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("readOnly", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("DCCIMetadataInterfaceType", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("DCCIMetadataInterface", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("version", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec DCCIClassFuncs[] = {
SMJS_FUNCTION_SPEC("hasProperty", dcci_has_property, 3),
diff --git a/src/scenegraph/svg_smjs.c b/src/scenegraph/svg_smjs.c
index 1f3d7c7..ce87087 100644
--- a/src/scenegraph/svg_smjs.c
+++ b/src/scenegraph/svg_smjs.c
@@ -1523,8 +1523,8 @@ static JSBool svg_connection_close(JSContext *c, JSObject *obj, uintN argc, jsva
}
static JSPropertySpec connectionProps[] = {
- {"connected", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("connected", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
static JSFunctionSpec connectionFuncs[] = {
/*eventTarget interface*/
@@ -2149,9 +2149,9 @@ static void svg_init_js_api(GF_SceneGraph *scene)
SMJS_SET_PRIVATE(scene->svg_js->js_ctx, scene->svg_js->global, scene);
{
JSPropertySpec globalClassProps[] = {
- {"connected", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"parent", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("connected", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("parent", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec globalClassFuncs[] = {
SMJS_FUNCTION_SPEC("createConnection", svg_connection_create, 0),
@@ -2180,9 +2180,8 @@ static void svg_init_js_api(GF_SceneGraph *scene)
JSPropertySpec svgDocumentProps[] = {
/*in our implementation, defaultView is just an alias to the global Window object*/
- {"defaultView", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
-
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("defaultView", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSObject *doc_proto = dom_js_get_document_proto(scene->svg_js->js_ctx);
GF_JS_InitClass(scene->svg_js->js_ctx, scene->svg_js->global, doc_proto, &svg_rt->svgDocument, 0, 0, svgDocumentProps, 0, 0, 0);
@@ -2248,21 +2247,21 @@ static void svg_init_js_api(GF_SceneGraph *scene)
JSPropertySpec svgElementProps[] = {
/*svgElement interface*/
- {"id", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
+ SMJS_PROPERTY_SPEC("id", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
/*svgSVGElement interface*/
- {"currentScale", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"currentRotate", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"currentTranslate", 7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"viewport", 8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"currentTime", 9, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
+ SMJS_PROPERTY_SPEC("currentScale", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("currentRotate", 6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("currentTranslate", 7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("viewport", 8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("currentTime", 9, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
/*timeControl interface*/
- {"isPaused", 10, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("isPaused", 10, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*old SVG1.1 stuff*/
- {"ownerSVGElement", 11, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
+ SMJS_PROPERTY_SPEC("ownerSVGElement", 11, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
/*SVGElementInstance*/
- {"correspondingElement", 12, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {"correspondingUseElement", 13, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("correspondingElement", 12, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC("correspondingUseElement", 13, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSObject *elt_proto = dom_js_get_element_proto(scene->svg_js->js_ctx);
GF_JS_InitClass(scene->svg_js->js_ctx, scene->svg_js->global, elt_proto, &svg_rt->svgElement, 0, 0, svgElementProps, svgElementFuncs, 0, 0);
@@ -2272,30 +2271,30 @@ static void svg_init_js_api(GF_SceneGraph *scene)
/*RGBColor class*/
{
JSPropertySpec rgbClassProps[] = {
- {"red", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"green", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"blue", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("red", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("green", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("blue", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
GF_JS_InitClass(scene->svg_js->js_ctx, scene->svg_js->global, 0, &svg_rt->rgbClass, 0, 0, rgbClassProps, 0, 0, 0);
}
/*SVGRect class*/
{
JSPropertySpec rectClassProps[] = {
- {"x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"width", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"height", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("width", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("height", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
GF_JS_InitClass(scene->svg_js->js_ctx, scene->svg_js->global, 0, &svg_rt->rectClass, 0, 0, rectClassProps, 0, 0, 0);
}
/*SVGPoint class*/
{
JSPropertySpec pointClassProps[] = {
- {"x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
GF_JS_InitClass(scene->svg_js->js_ctx, scene->svg_js->global, 0, &svg_rt->pointClass, 0, 0, pointClassProps, 0, 0, 0);
}
@@ -2311,13 +2310,13 @@ static void svg_init_js_api(GF_SceneGraph *scene)
SMJS_FUNCTION_SPEC(0, 0, 0)
};
JSPropertySpec matrixClassProps[] = {
- {"a", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"b", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"c", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"d", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"e", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"f", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("a", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("b", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("c", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("d", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("e", 4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("f", 5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
GF_JS_InitClass(scene->svg_js->js_ctx, scene->svg_js->global, 0, &svg_rt->matrixClass, 0, 0, matrixClassProps, matrixClassFuncs, 0, 0);
}
@@ -2334,8 +2333,8 @@ static void svg_init_js_api(GF_SceneGraph *scene)
SMJS_FUNCTION_SPEC(0, 0, 0)
};
JSPropertySpec pathClassProps[] = {
- {"numberOfSegments", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("numberOfSegments", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
GF_JS_InitClass(scene->svg_js->js_ctx, scene->svg_js->global, 0, &svg_rt->pathClass, 0, 0, pathClassProps, pathClassFuncs, 0, 0);
JS_DefineProperty(scene->svg_js->js_ctx, svg_rt->pathClass._proto, "MOVE_TO", INT_TO_JSVAL(77), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT);
diff --git a/src/scenegraph/vrml_smjs.c b/src/scenegraph/vrml_smjs.c
index 45a6262..ffde778 100644
--- a/src/scenegraph/vrml_smjs.c
+++ b/src/scenegraph/vrml_smjs.c
@@ -291,6 +291,7 @@ static void gf_sg_load_script_modules(GF_SceneGraph *sg)
if (!ext) continue;
gf_list_add(js_rt->extensions, ext);
}
+ GF_LOG(GF_LOG_INFO, GF_LOG_SCRIPT, ("[ECMAScript] found %d JS extensions for %d modules\n", gf_list_count(js_rt->extensions), count));
}
static void gf_sg_unload_script_modules()
@@ -3119,17 +3120,17 @@ void gf_sg_script_init_sm_api(GF_ScriptPriv *sc, GF_Node *script)
#else
/*only used to debug JS_SETUP_CLASS at each of the numerous changes of JSAPI ............ */
memset(&js_rt->SFNodeClass, 0, sizeof(js_rt->SFNodeClass));
- js_rt->SFNodeClass.name = "SFNode";
- js_rt->SFNodeClass.flags = JSCLASS_HAS_PRIVATE;
- js_rt->SFNodeClass.addProperty = JS_PropertyStub;
- js_rt->SFNodeClass.delProperty = JS_PropertyStub;
- js_rt->SFNodeClass.getProperty = node_getProperty;
- js_rt->SFNodeClass.setProperty = node_setProperty;
- js_rt->SFNodeClass.enumerate = JS_EnumerateStub;
- js_rt->SFNodeClass.resolve = JS_ResolveStub;
- js_rt->SFNodeClass.convert = JS_ConvertStub;
- js_rt->SFNodeClass.finalize = node_finalize;
- js_rt->SFNodeClass.hasInstance = gf_sg_js_has_instance;
+ js_rt->SFNodeClass._class.name = "SFNode";
+ js_rt->SFNodeClass._class.flags = JSCLASS_HAS_PRIVATE;
+ js_rt->SFNodeClass._class.addProperty = JS_PropertyStub;
+ js_rt->SFNodeClass._class.delProperty = JS_PropertyStub;
+ js_rt->SFNodeClass._class.getProperty = node_getProperty;
+ js_rt->SFNodeClass._class.setProperty = node_setProperty;
+ js_rt->SFNodeClass._class.enumerate = JS_EnumerateStub;
+ js_rt->SFNodeClass._class.resolve = JS_ResolveStub;
+ js_rt->SFNodeClass._class.convert = JS_ConvertStub;
+ js_rt->SFNodeClass._class.finalize = node_finalize;
+ js_rt->SFNodeClass._class.hasInstance = gf_sg_js_has_instance;
#endif
JS_SETUP_CLASS(js_rt->SFVec2fClass , "SFVec2f", JSCLASS_HAS_PRIVATE,
@@ -3244,16 +3245,16 @@ void gf_sg_script_init_sm_api(GF_ScriptPriv *sc, GF_Node *script)
SMJS_FUNCTION_SPEC(0, 0, 0)
};
JSPropertySpec SFNodeProps[] = {
- {"__dummy", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("__dummy", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
GF_JS_InitClass(sc->js_ctx, sc->js_obj, 0, &js_rt->SFNodeClass, SFNodeConstructor, 1, SFNodeProps, SFNodeMethods, 0, 0);
}
{
JSPropertySpec SFVec2fProps[] = {
- {"x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec SFVec2fMethods[] = {
SMJS_FUNCTION_SPEC("add", vec2f_add, 1),
@@ -3271,10 +3272,10 @@ void gf_sg_script_init_sm_api(GF_ScriptPriv *sc, GF_Node *script)
}
{
JSPropertySpec SFVec3fProps[] = {
- {"x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"z", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("z", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec SFVec3fMethods[] = {
SMJS_FUNCTION_SPEC("add", vec3f_add, 1),
@@ -3293,11 +3294,11 @@ void gf_sg_script_init_sm_api(GF_ScriptPriv *sc, GF_Node *script)
}
{
JSPropertySpec SFRotationProps[] = {
- {"xAxis", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"yAxis", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"zAxis", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"angle", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("xAxis", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("yAxis", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("zAxis", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("angle", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec SFRotationMethods[] = {
SMJS_FUNCTION_SPEC("getAxis", rot_getAxis, 1),
@@ -3313,10 +3314,10 @@ void gf_sg_script_init_sm_api(GF_ScriptPriv *sc, GF_Node *script)
}
{
JSPropertySpec SFColorProps[] = {
- {"r", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"g", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"b", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("r", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("g", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("b", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
JSFunctionSpec SFColorMethods[] = {
SMJS_FUNCTION_SPEC("setHSV", color_setHSV, 3),
@@ -3328,20 +3329,20 @@ void gf_sg_script_init_sm_api(GF_ScriptPriv *sc, GF_Node *script)
}
{
JSPropertySpec SFImageProps[] = {
- {"x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"comp", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {"array", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0},
- {0, 0, 0, 0, 0}
+ SMJS_PROPERTY_SPEC("x", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("y", 1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("comp", 2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC("array", 3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0),
+ SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0)
};
GF_JS_InitClass(sc->js_ctx, sc->js_obj, 0, &js_rt->SFImageClass, SFImageConstructor, 0, SFImageProps, 0, 0, 0);
}
{
JSPropertySpec MFArrayProp[] = {
- { "length", 0, JSPROP_PERMANENT | JSPROP_SHARED, array_getLength, array_setLength },
- { "assign", 1, JSPROP_PERMANENT | JSPROP_SHARED, array_getElement, array_setElement},
- { 0, 0, 0, 0, 0 }
+ SMJS_PROPERTY_SPEC( "length", 0, JSPROP_PERMANENT | JSPROP_SHARED, array_getLength, array_setLength ),
+ SMJS_PROPERTY_SPEC( "assign", 1, JSPROP_PERMANENT | JSPROP_SHARED, array_getElement, array_setElement),
+ SMJS_PROPERTY_SPEC( 0, 0, 0, 0, 0 )
};
JSFunctionSpec MFArrayMethods[] = {
SMJS_FUNCTION_SPEC("toString", field_toString, 0),
diff --git a/src/terminal/decoder.c b/src/terminal/decoder.c
index f18a433..8c8f895 100644
--- a/src/terminal/decoder.c
+++ b/src/terminal/decoder.c
@@ -669,8 +669,12 @@ static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable)
if ( LockCompositionUnit(codec, codec->last_unit_cts+1, &CU, &unit_size) == GF_OUT_OF_MEM)
return GF_OK;
assert( CU );
+ unit_size = 0;
e = mdec->ProcessData(mdec, NULL, 0, 0, CU->data, &unit_size, 0, 0);
- if (e==GF_OK) e = UnlockCompositionUnit(codec, CU, unit_size);
+ if (e==GF_OK) {
+ e = UnlockCompositionUnit(codec, CU, unit_size);
+ if (unit_size) return GF_OK;
+ }
}
gf_term_stop_codec(codec, 0);
if (codec->CB) gf_cm_set_eos(codec->CB);
@@ -939,7 +943,7 @@ drop:
}
Decoder_GetNextAU(codec, &ch, &AU);
if (!ch || !AU) return GF_OK;
- }
+ }
return GF_OK;
}
diff --git a/src/terminal/media_manager.c b/src/terminal/media_manager.c
index 21d782d..a09dd2e 100644
--- a/src/terminal/media_manager.c
+++ b/src/terminal/media_manager.c
@@ -140,15 +140,23 @@ void gf_term_add_codec(GF_Terminal *term, GF_Codec *codec)
cd->dec = codec;
if (!cd->dec->Priority)
cd->dec->Priority = 1;
-
- cap.CapCode = GF_CODEC_WANTS_THREAD;
- cap.cap.valueInt = 0;
- gf_codec_get_capability(codec, &cap);
- threaded = cap.cap.valueInt;
+
+ /*we force audio codecs to be threaded in free mode, so that we avoid waiting in the audio renderer if another decoder is locking the main mutex
+ this can happen when the audio decoder is running late*/
+ if (codec->type==GF_STREAM_AUDIO) {
+ threaded = 1;
+ } else {
+ cap.CapCode = GF_CODEC_WANTS_THREAD;
+ cap.cap.valueInt = 0;
+ gf_codec_get_capability(codec, &cap);
+ threaded = cap.cap.valueInt;
+ }
+
if (threaded) cd->flags |= GF_MM_CE_REQ_THREAD;
+
if (term->flags & GF_TERM_MULTI_THREAD) {
- if ((codec->type==0x04) || (codec->type==0x05)) threaded = 1;
+ if ((codec->type==GF_STREAM_AUDIO) || (codec->type==GF_STREAM_VISUAL)) threaded = 1;
} else if (term->flags & GF_TERM_SINGLE_THREAD) {
threaded = 0;
}
diff --git a/src/terminal/media_memory.c b/src/terminal/media_memory.c
index 3903b15..9101848 100644
--- a/src/terminal/media_memory.c
+++ b/src/terminal/media_memory.c
@@ -414,6 +414,7 @@ void gf_cm_resize(GF_CompositionMemory *cb, u32 newCapacity)
if (!cb->no_allocation) {
my_large_gf_free(cu->data);
cu->data = (char*) my_large_alloc(newCapacity);
+ cu->dataLength = 0;
} else {
cu->data = NULL;
if (cu->dataLength && cb->odm->raw_frame_sema) {
@@ -429,9 +430,12 @@ void gf_cm_resize(GF_CompositionMemory *cb, u32 newCapacity)
} else {
cu->data = NULL;
}
+ cu->dataLength = 0;
cu = cu->next;
- }
-
+ }
+
+ cb->UnitCount = 0;
+ cb->output = cb->input;
gf_odm_lock(cb->odm, 0);
}
diff --git a/src/terminal/network_service.c b/src/terminal/network_service.c
index 3b56074..1ba90cb 100644
--- a/src/terminal/network_service.c
+++ b/src/terminal/network_service.c
@@ -82,7 +82,7 @@ static void term_on_connect(void *user_priv, GF_ClientService *service, LPNETCHA
gf_term_service_media_event(service->owner, GF_EVENT_MEDIA_SETUP_DONE);
if (err) {
char msg[5000];
- snprintf(msg, sizeof(msg), "Cannot open %s", service->url);
+ snprintf(msg, sizeof(msg)-1, "Cannot open %s", service->url);
gf_term_message(term, service->url, msg, err);
gf_term_service_media_event(service->owner, GF_EVENT_ERROR);
diff --git a/src/terminal/object_manager.c b/src/terminal/object_manager.c
index da429aa..49eebf4 100644
--- a/src/terminal/object_manager.c
+++ b/src/terminal/object_manager.c
@@ -314,9 +314,23 @@ void gf_odm_setup_entry_point(GF_ObjectManager *odm, const char *service_sub_url
}
desc = odm->net_service->ifce->GetServiceDescriptor(odm->net_service->ifce, od_type, sub_url);
- if (odm->OD) return;
+
+ /*entry point is already setup (bad design in GPAC, happens with BIFS TS and DASH*/
+ if (odm->OD) {
+ if (!desc) return;
+ if (gf_list_count(odm->OD->ESDescriptors)) {
+ gf_odf_desc_del(desc);
+ return;
+ }
+ gf_odf_desc_del((GF_Descriptor *) odm->OD);
+ odm->OD=NULL;
+ odm->subscene->is_dynamic_scene = 0;
+ }
if (!desc) {
+ if (odm->OD && !gf_list_count(odm->OD->ESDescriptors))
+ return;
+
/*if desc is NULL for a media, the media will be declared later by the service (gf_term_media_add)*/
if (od_type != GF_MEDIA_OBJECT_SCENE) {
return;
diff --git a/src/terminal/scene.c b/src/terminal/scene.c
index 64cfe1f..3540971 100644
--- a/src/terminal/scene.c
+++ b/src/terminal/scene.c
@@ -947,7 +947,6 @@ void gf_scene_register_extra_graph(GF_Scene *scene, GF_SceneGraph *extra_scene,
}
-
static void gf_scene_get_video_size(GF_MediaObject *mo, u32 *w, u32 *h)
{
u32 pixel_ar;
@@ -994,7 +993,7 @@ static void IS_UpdateVideoPos(GF_Scene *scene)
if (scene->root_od->term->root_scene == scene) {
//if (scene->graph_attached) gf_sc_set_scene(scene->root_od->term->compositor, NULL);
- gf_sc_set_scene(scene->root_od->term->compositor, scene->graph);
+ //gf_sc_set_scene(scene->root_od->term->compositor, scene->graph);
}
}
@@ -1372,7 +1371,20 @@ void gf_scene_force_size(GF_Scene *scene, u32 width, u32 height)
gf_sg_set_scene_size_info(scene->graph, width, height, gf_sg_use_pixel_metrics(scene->graph));
if (scene->root_od->term->root_scene == scene) {
- gf_sc_set_scene(scene->root_od->term->compositor, scene->graph);
+ GF_NetworkCommand com;
+
+ gf_sc_set_scene_size(scene->root_od->term->compositor, width, height, 1);
+
+ memset(&com, 0, sizeof(GF_NetworkCommand));
+ com.base.command_type = GF_NET_SERVICE_HAS_FORCED_VIDEO_SIZE;
+ gf_term_service_command(scene->root_od->net_service, &com);
+ if (com.par.width && com.par.height) {
+ gf_sc_set_size(scene->root_od->term->compositor, com.par.width, com.par.height);
+ } else {
+ /*need output resize*/
+ gf_sc_set_scene(scene->root_od->term->compositor, scene->graph);
+ gf_sc_set_size(scene->root_od->term->compositor, width, height);
+ }
}
else if (scene->root_od->parentscene && scene->root_od->parentscene->is_dynamic_scene) {
gf_sg_set_scene_size_info(scene->root_od->parentscene->graph, width, height, gf_sg_use_pixel_metrics(scene->root_od->parentscene->graph));
diff --git a/src/utils/base_encoding.c b/src/utils/base_encoding.c
index cb92a1b..97afacb 100644
--- a/src/utils/base_encoding.c
+++ b/src/utils/base_encoding.c
@@ -174,6 +174,9 @@ u32 gf_base16_decode(char *in, u32 inSize, char *out, u32 outSize)
return j;
}
+
+#ifndef GPAC_DISABLE_ZLIB
+
#include
#define ZLIB_COMPRESS_SAFE 4
@@ -266,3 +269,5 @@ GF_Err gf_gz_decompress_payload(char *data, u32 data_len, char **uncompressed_da
}
return e;
}
+
+#endif /*GPAC_DISABLE_ZLIB*/
diff --git a/src/utils/cache.c b/src/utils/cache.c
index 7b08685..1e84ea4 100644
--- a/src/utils/cache.c
+++ b/src/utils/cache.c
@@ -156,6 +156,17 @@ struct __DownloadedCacheEntryStruct
/*start and end range of the cache*/
u64 range_start, range_end;
+ Bool continue_file;
+ Bool file_exists;
+
+ u32 previousRangeContentLength;
+
+ /**
+ * Set to 1 if file is not stored on disk
+ */
+ Bool memory_stored;
+ u32 mem_allocated;
+ u8 *mem_storage;
};
Bool delete_cache_files(void *cbck, char *item_name, char *item_path) {
@@ -362,7 +373,7 @@ static const char * default_cache_file_suffix = ".dat";
static const char * cache_file_info_suffix = ".txt";
-DownloadedCacheEntry gf_cache_create_entry ( GF_DownloadManager * dm, const char * cache_directory, const char * url , u64 start_range, u64 end_range)
+DownloadedCacheEntry gf_cache_create_entry ( GF_DownloadManager * dm, const char * cache_directory, const char * url , u64 start_range, u64 end_range, Bool mem_storage)
{
char tmp[_CACHE_TMP_SIZE];
u8 hash[_CACHE_HASH_SIZE];
@@ -408,14 +419,12 @@ DownloadedCacheEntry gf_cache_create_entry ( GF_DownloadManager * dm, const char
GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("gf_cache_create_entry:%d : OUT of memory !\n", __LINE__));
return NULL;
}
- GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK,
- ("[CACHE] gf_cache_create_entry:%d, entry=%p\n", __LINE__, entry));
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d, entry=%p\n", __LINE__, entry));
entry->url = gf_strdup ( url );
entry->hash = gf_strdup ( tmp );
- /* Sizeof cache directory + hash + possible extension */
- entry->cache_filename = gf_malloc ( strlen ( cache_directory ) + strlen(cache_file_prefix) + strlen(tmp) + _CACHE_MAX_EXTENSION_SIZE + 1);
+ entry->memory_stored = mem_storage;
entry->cacheSize = 0;
entry->contentLength = 0;
@@ -429,17 +438,26 @@ DownloadedCacheEntry gf_cache_create_entry ( GF_DownloadManager * dm, const char
entry->range_start = start_range;
entry->range_end = end_range;
+#ifdef ENABLE_WRITE_MX
{
char name[1024];
- snprintf(name, 1024, "CachedEntryWriteMx=%p, url=%s", (void*) entry, url);
-#ifdef ENABLE_WRITE_MX
+ snprintf(name, sizeof(name)-1, "CachedEntryWriteMx=%p, url=%s", (void*) entry, url);
entry->write_mutex = gf_mx_new(name);
assert( entry->write_mutex);
-#endif
}
+#endif
+
entry->deletableFilesOnDelete = 0;
entry->write_session = NULL;
entry->sessions = gf_list_new();
+
+ if (entry->memory_stored) {
+ entry->cache_filename = gf_malloc ( strlen ("gmem://") + 8 + strlen("@") + 16 + 1);
+ } else {
+ /* Sizeof cache directory + hash + possible extension */
+ entry->cache_filename = gf_malloc ( strlen ( cache_directory ) + strlen(cache_file_prefix) + strlen(tmp) + _CACHE_MAX_EXTENSION_SIZE + 1);
+ }
+
if ( !entry->hash || !entry->url || !entry->cache_filename || !entry->sessions)
{
GF_Err err;
@@ -449,6 +467,13 @@ DownloadedCacheEntry gf_cache_create_entry ( GF_DownloadManager * dm, const char
assert ( err == GF_OK );
return NULL;
}
+
+ if (entry->memory_stored) {
+ sprintf(entry->cache_filename, "gmem://%d@%p", entry->contentLength, entry->mem_storage);
+ return entry;
+ }
+
+
tmp[0] = '\0';
strcpy ( entry->cache_filename, cache_directory );
strcat( entry->cache_filename, cache_file_prefix );
@@ -497,7 +522,13 @@ DownloadedCacheEntry gf_cache_create_entry ( GF_DownloadManager * dm, const char
entry->flags |= CORRUPTED;
keyValue = gf_cfg_get_key(entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_RANGE);
- if (keyValue) sscanf(keyValue, LLD"-"LLD, &entry->range_start, &entry->range_end);
+ if (keyValue) {
+ u64 s, e;
+ sscanf(keyValue, LLD"-"LLD, &s, &e);
+ /*mark as corrupted if not same range (we don't support this for the time being ...*/
+ if ((s!=entry->range_start) || (e!=entry->range_end))
+ entry->flags |= CORRUPTED;
+ }
}
gf_cache_check_if_cache_file_is_corrupted(entry);
@@ -506,7 +537,11 @@ DownloadedCacheEntry gf_cache_create_entry ( GF_DownloadManager * dm, const char
GF_Err gf_cache_set_content_length( const DownloadedCacheEntry entry, u32 length ) {
CHECK_ENTRY;
- entry->contentLength = length;
+ if (entry->continue_file) {
+ entry->contentLength = entry->previousRangeContentLength + length;
+ } else {
+ entry->contentLength = length;
+ }
return GF_OK;
}
@@ -557,10 +592,31 @@ GF_Err gf_cache_open_write_cache( const DownloadedCacheEntry entry, const GF_Dow
gf_mx_p(entry->write_mutex);
#endif
entry->write_session = sess;
- assert( ! entry->writeFilePtr);
- GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK,
- ("[CACHE] Opening cache file %s for write (%s)...\n", entry->cache_filename, entry->url));
- entry->writeFilePtr = gf_f64_open(entry->cache_filename, "wb");
+ if (!entry->continue_file) {
+ assert( ! entry->writeFilePtr);
+
+ entry->written_in_cache = 0;
+ }
+ entry->flags &= ~CORRUPTED;
+
+
+ if (entry->memory_stored) {
+ GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] Opening cache file %s for write (%s)...\n", entry->cache_filename, entry->url));
+ if (entry->mem_allocated <= entry->contentLength) {
+ if (entry->contentLength) entry->mem_allocated = entry->contentLength;
+ else if (!entry->mem_allocated) entry->mem_allocated = 1024;
+ entry->mem_storage = gf_realloc(entry->mem_storage, sizeof(char)* (entry->mem_allocated + 2) );
+ }
+ if (!entry->mem_allocated) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Failed to create memory storage for file %s\n", entry->url));
+ return GF_OUT_OF_MEM;
+ }
+ sprintf(entry->cache_filename, "gmem://%d@%p", entry->contentLength, entry->mem_storage);
+ return GF_OK;
+ }
+
+ GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] Opening cache file %s for write (%s)...\n", entry->cache_filename, entry->url));
+ entry->writeFilePtr = gf_f64_open(entry->cache_filename, entry->continue_file ? "a+b" : "wb");
if (!entry->writeFilePtr) {
GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK,
("[CACHE] Error while opening cache file %s for writting.\n", entry->cache_filename));
@@ -570,7 +626,9 @@ GF_Err gf_cache_open_write_cache( const DownloadedCacheEntry entry, const GF_Dow
#endif
return GF_IO_ERR;
}
- entry->written_in_cache = 0;
+ entry->file_exists = 1;
+ if (entry->continue_file )
+ gf_f64_seek(entry->writeFilePtr, 0, SEEK_END);
return GF_OK;
}
@@ -578,10 +636,24 @@ GF_Err gf_cache_write_to_cache( const DownloadedCacheEntry entry, const GF_Downl
u32 readen;
GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[CACHE] gf_cache_write_to_cache:%d\n", __LINE__));
CHECK_ENTRY;
- if (!data || !entry->writeFilePtr || sess != entry->write_session) {
- GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("Incorrect parameter : data=%p, entry->writeFilePtr=%p at "__FILE__, data, entry->writeFilePtr));
+
+ if (!data || (!entry->writeFilePtr && !entry->mem_storage) || sess != entry->write_session) {
+ GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("Incorrect parameter : data=%p, writeFilePtr=%p mem_storage=%p at "__FILE__, data, entry->writeFilePtr, entry->mem_storage));
return GF_BAD_PARAM;
}
+
+ if (entry->memory_stored) {
+ if (entry->written_in_cache + size > entry->mem_allocated) {
+ entry->mem_storage = gf_realloc(entry->mem_storage, (entry->mem_allocated+size+2));
+ entry->mem_allocated += size;
+ sprintf(entry->cache_filename, "gmem://%d@%p", entry->contentLength, entry->mem_storage);
+ }
+ memcpy(entry->mem_storage + entry->written_in_cache, data, size);
+ entry->written_in_cache += size;
+ memset(entry->mem_storage + entry->written_in_cache, 0, 2);
+ return GF_OK;
+ }
+
readen = gf_fwrite(data, sizeof(char), size, entry->writeFilePtr);
if (readen > 0)
entry->written_in_cache+= readen;
@@ -671,7 +743,7 @@ GF_Err gf_cache_delete_entry ( const DownloadedCacheEntry entry )
gf_mx_del(entry->write_mutex);
}
#endif
- if (entry->deletableFilesOnDelete) {
+ if (entry->file_exists && entry->deletableFilesOnDelete) {
GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] url %s cleanup, deleting %s...\n", entry->url, entry->cache_filename));
if (GF_OK != gf_delete_file(entry->cache_filename))
GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[CACHE] gf_cache_delete_entry:%d, failed to delete file %s\n", __LINE__, entry->cache_filename));
@@ -738,6 +810,9 @@ GF_Err gf_cache_delete_entry ( const DownloadedCacheEntry entry )
gf_list_del(entry->sessions);
entry->sessions = NULL;
}
+
+ if (entry->mem_storage)
+ gf_free(entry->mem_storage);
gf_free (entry);
return GF_OK;
}
@@ -757,17 +832,15 @@ Bool gf_cache_check_if_cache_file_is_corrupted(const DownloadedCacheEntry entry)
entry->contentLength = strtoul( keyValue, &endPtr, 10);
if (*endPtr!='\0' || entry->contentLength != entry->cacheSize) {
entry->flags |= CORRUPTED;
- GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d, cached file and cache info size mismatch.\n", __LINE__));
+ GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d, Cache corrupted: file and cache info size mismatch.\n", __LINE__));
}
- } else
+ } else {
entry->flags |= CORRUPTED;
-
+ GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d, CACHE is corrupted !\n", __LINE__));
+ }
} else {
entry->flags |= CORRUPTED;
}
- if (entry->flags & CORRUPTED)
- GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d, CACHE is corrupted !\n", __LINE__));
-
return entry->flags & CORRUPTED;
}
@@ -832,3 +905,20 @@ FILE *gf_cache_get_file_pointer(const DownloadedCacheEntry entry)
if (entry) return entry->writeFilePtr;
return NULL;
}
+
+
+void gf_cache_set_end_range(DownloadedCacheEntry entry, u64 range_end)
+{
+ entry->previousRangeContentLength = entry->contentLength;
+ entry->range_end = range_end;
+ entry->continue_file = 1;
+}
+
+Bool gf_cache_is_in_progress(const DownloadedCacheEntry entry)
+{
+ if (!entry) return 0;
+ if (entry->writeFilePtr) return 1;
+ if (entry->mem_storage && entry->written_in_cache && entry->contentLength && (entry->written_in_cachecontentLength) )
+ return 1;
+ return 0;
+}
diff --git a/src/utils/configfile.c b/src/utils/configfile.c
index c502d4f..ebcbe30 100644
--- a/src/utils/configfile.c
+++ b/src/utils/configfile.c
@@ -207,7 +207,8 @@ GF_Config *gf_cfg_new(const char *filePath, const char* file_name)
}
if (gf_cfg_parse_config_file(tmp, filePath, file_name)){
- gf_free( tmp );
+ gf_cfg_clear(tmp);
+ gf_free(tmp);
tmp = NULL;
}
return tmp;
diff --git a/src/utils/downloader.c b/src/utils/downloader.c
index bf8f1ff..ccdde23 100644
--- a/src/utils/downloader.c
+++ b/src/utils/downloader.c
@@ -108,6 +108,7 @@ struct __gf_download_session
gf_user_credentials_struct * creds;
char cookie[GF_MAX_PATH];
DownloadedCacheEntry cache_entry;
+ Bool reused_cache_entry;
GF_Socket *sock;
u32 num_retry, status;
@@ -117,6 +118,9 @@ struct __gf_download_session
u32 total_size, bytes_done, start_time, icy_metaint, icy_count, icy_bytes;
u32 bytes_per_sec;
+ Bool is_range_continuation;
+ /*0: no cache reconfig before next GET request: 1: try to rematch the cache entry: 2: force to create a new cache entry (for byte-range cases*/
+ u32 needs_cache_reconfig;
/* Range information if needed for the download (cf flag) */
Bool needs_range;
u64 range_start, range_end;
@@ -145,6 +149,7 @@ struct __gf_download_session
/*callback for data reception - may not be NULL*/
gf_dm_user_io user_proc;
void *usr_cbk;
+ Bool reassigned;
/*private extension*/
void *ext;
@@ -241,6 +246,12 @@ GF_Err gf_cache_open_write_cache( const DownloadedCacheEntry entry, const GF_Dow
*/
FILE *gf_cache_get_file_pointer(const DownloadedCacheEntry entry) ;
+/*modify end range when chaining byte-range requests*/
+void gf_cache_set_end_range(DownloadedCacheEntry entry, u64 range_end);
+
+/*returns 1 if cache is currently open for write*/
+Bool gf_cache_is_in_progress(const DownloadedCacheEntry entry);
+
/**
* Find a User's credentials for a given site
*/
@@ -455,8 +466,13 @@ DownloadedCacheEntry gf_dm_find_cached_entry_by_url(GF_DownloadSession * sess) {
url = gf_cache_get_url(e);
assert( url );
if (strcmp(url, sess->orig_url)) continue;
- if (sess->range_start != gf_cache_get_start_range(e)) continue;
- if (sess->range_end != gf_cache_get_end_range(e)) continue;
+ if (sess->needs_cache_reconfig==2)
+ continue;
+
+ if (! sess->is_range_continuation) {
+ if (sess->range_start != gf_cache_get_start_range(e)) continue;
+ if (sess->range_end != gf_cache_get_end_range(e)) continue;
+ }
/*OK that's ours*/
gf_mx_v( sess->dm->cache_mx );
return e;
@@ -471,7 +487,7 @@ DownloadedCacheEntry gf_dm_find_cached_entry_by_url(GF_DownloadSession * sess) {
* \param url The full URL
* \return The DownloadedCacheEntry
*/
-DownloadedCacheEntry gf_cache_create_entry( GF_DownloadManager * dm, const char * cache_directory, const char * url, u64 start_range, u64 end_range);
+DownloadedCacheEntry gf_cache_create_entry( GF_DownloadManager * dm, const char * cache_directory, const char * url, u64 start_range, u64 end_range, Bool mem_storage);
/*!
* Removes a session for a DownloadedCacheEntry
@@ -528,13 +544,15 @@ void gf_dm_configure_cache(GF_DownloadSession *sess)
gf_dm_remove_cache_entry_from_session(sess);
entry = gf_dm_find_cached_entry_by_url(sess);
if (!entry) {
- entry = gf_cache_create_entry(sess->dm, sess->dm->cache_directory, sess->orig_url, sess->range_start, sess->range_end);
+ entry = gf_cache_create_entry(sess->dm, sess->dm->cache_directory, sess->orig_url, sess->range_start, sess->range_end, (sess->flags&GF_NETIO_SESSION_MEMORY_CACHE) ? 1 : 0);
gf_mx_p( sess->dm->cache_mx );
gf_list_add(sess->dm->cache_entries, entry);
gf_mx_v( sess->dm->cache_mx );
+ sess->is_range_continuation = 0;
}
assert( entry );
sess->cache_entry = entry;
+ sess->reused_cache_entry = gf_cache_is_in_progress(entry);
gf_cache_add_session_to_cache_entry(sess->cache_entry, sess);
GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] Cache setup to %p %s\n", sess, gf_cache_get_cache_filename(sess->cache_entry)));
}
@@ -598,7 +616,7 @@ static void gf_dm_disconnect(GF_DownloadSession *sess, Bool force_close)
{
assert( sess );
if (sess->status >= GF_NETIO_DISCONNECTED)
- return;
+ return;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Downloader] gf_dm_disconnect(%p)\n", sess ));
if (sess->mx)
gf_mx_p(sess->mx);
@@ -858,8 +876,8 @@ GF_Err gf_dm_get_url_info(const char * url, GF_URL_Info * info, const char * bas
/* builds orig_url */
/* We dont't want orig_url to contain user/passwords for security reasons or mismatch in cache hit */
{
- char port[7];
- snprintf(port, 7, ":%d", info->port);
+ char port[8];
+ snprintf(port, sizeof(port)-1, ":%d", info->port);
info->canonicalRepresentation = gf_malloc(strlen(info->protocol)+strlen(info->server_name)+1+strlen(port)+strlen(info->remotePath));
strcpy(info->canonicalRepresentation, info->protocol);
strcat(info->canonicalRepresentation, info->server_name);
@@ -878,13 +896,17 @@ GF_Err gf_dm_sess_setup_from_url(GF_DownloadSession *sess, const char *url)
Bool socket_changed = 0;
GF_Err e;
GF_URL_Info info;
+
+ if (!url) return GF_BAD_PARAM;
+
gf_dm_url_info_init(&info);
- e = gf_dm_get_url_info(url, &info, sess->remote_path);
- if (e) return e;
if (!sess->sock) socket_changed = 1;
else if (sess->status>GF_NETIO_DISCONNECTED) socket_changed = 1;
+ e = gf_dm_get_url_info(url, &info, sess->remote_path);
+ if (e) return e;
+
if (sess->port != info.port) {
socket_changed = 1;
sess->port = info.port;
@@ -939,8 +961,7 @@ GF_Err gf_dm_sess_setup_from_url(GF_DownloadSession *sess, const char *url)
if (sess->sock && !socket_changed) {
sess->status = GF_NETIO_CONNECTED;
sess->num_retry = SESSION_RETRY_COUNT;
- /*this should be done when building HTTP GET request in case we have range directives*/
- gf_dm_configure_cache(sess);
+ sess->needs_cache_reconfig = 1;
} else {
if (sess->sock) gf_sk_del(sess->sock);
sess->sock = NULL;
@@ -1039,8 +1060,10 @@ GF_DownloadSession *gf_dm_sess_new(GF_DownloadManager *dm, const char *url, u32
static GF_Err gf_dm_read_data(GF_DownloadSession *sess, char *data, u32 data_size, u32 *out_read)
{
+#ifdef GPAC_HAS_SSL
GF_Err e;
- if (!sess)
+#endif
+ if (!sess)
return GF_BAD_PARAM;
#ifdef GPAC_HAS_SSL
if (sess->ssl) {
@@ -1325,11 +1348,34 @@ const char *gf_dm_sess_mime_type(GF_DownloadSession *sess)
}
GF_EXPORT
-GF_Err gf_dm_sess_set_range(GF_DownloadSession *sess, u64 start_range, u64 end_range)
+GF_Err gf_dm_sess_set_range(GF_DownloadSession *sess, u64 start_range, u64 end_range, Bool discontinue_cache)
{
if (!sess) return GF_BAD_PARAM;
- if (sess->cache_entry) return GF_BAD_PARAM;
- if (sess->status != GF_NETIO_SETUP) return GF_BAD_PARAM;
+ if (sess->cache_entry) {
+ if (!discontinue_cache) {
+ if (gf_cache_get_end_range(sess->cache_entry) + 1 != start_range)
+ return GF_NOT_SUPPORTED;
+ }
+ if (!sess->sock)
+ return GF_BAD_PARAM;
+ if (sess->status != GF_NETIO_CONNECTED) {
+ if (sess->status != GF_NETIO_DISCONNECTED) {
+ return GF_BAD_PARAM;
+ }
+ }
+ sess->status = GF_NETIO_CONNECTED;
+ sess->num_retry = SESSION_RETRY_COUNT;
+ if (!discontinue_cache) {
+ gf_cache_set_end_range(sess->cache_entry, end_range);
+ /*remember this in case we get disconnected*/
+ sess->is_range_continuation = 1;
+ } else {
+ sess->needs_cache_reconfig = 2;
+ sess->reused_cache_entry = 0;
+ }
+ } else {
+ if (sess->status != GF_NETIO_SETUP) return GF_BAD_PARAM;
+ }
sess->range_start = start_range;
sess->range_end = end_range;
sess->needs_range = 1;
@@ -1393,7 +1439,8 @@ GF_Err gf_dm_sess_process_headers(GF_DownloadSession *sess)
gf_sleep(16);
break;
case GF_NETIO_WAIT_FOR_REPLY:
- gf_sleep(16);
+// gf_sleep(16);
+ gf_sleep(1);
case GF_NETIO_CONNECTED:
sess->do_requests(sess);
break;
@@ -1666,18 +1713,6 @@ static GFINLINE void gf_dm_data_received(GF_DownloadSession *sess, const char *d
}
}
- if (sess->total_size && (sess->bytes_done == sess->total_size)) {
- gf_dm_disconnect(sess, 0);
- par.msg_type = GF_NETIO_DATA_TRANSFERED;
- par.error = GF_OK;
- gf_dm_sess_user_io(sess, &par);
- if (sess->use_cache_file) {
- gf_cache_close_write_cache(sess->cache_entry, sess, 1);
- GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK,
- ("[CACHE] url %s saved as %s\n", gf_cache_get_url(sess->cache_entry), gf_cache_get_cache_filename(sess->cache_entry)));
- }
- return;
- }
/*update state if not done*/
if (rcv) {
runtime = gf_sys_clock() - sess->start_time;
@@ -1687,6 +1722,21 @@ static GFINLINE void gf_dm_data_received(GF_DownloadSession *sess, const char *d
sess->bytes_per_sec = (1000 * sess->bytes_done) / runtime;
}
}
+
+ if (sess->total_size && (sess->bytes_done == sess->total_size)) {
+ gf_dm_disconnect(sess, 0);
+ par.msg_type = GF_NETIO_DATA_TRANSFERED;
+ par.error = GF_OK;
+
+
+ gf_dm_sess_user_io(sess, &par);
+ if (sess->use_cache_file) {
+ gf_cache_close_write_cache(sess->cache_entry, sess, 1);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK,
+ ("[CACHE] url %s saved as %s\n", gf_cache_get_url(sess->cache_entry), gf_cache_get_cache_filename(sess->cache_entry)));
+ }
+ GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] url %s downloaded in %d ms (%d kbps)\n", gf_cache_get_url(sess->cache_entry), gf_sys_clock() - sess->start_time, 8*sess->bytes_per_sec/1024 ));
+ }
}
@@ -1823,6 +1873,13 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) {
const char *param_string;
Bool has_accept, has_connection, has_range, has_agent, has_language, send_profile, has_mime;
assert (sess->status == GF_NETIO_CONNECTED);
+
+
+ if (sess->needs_cache_reconfig) {
+ gf_dm_configure_cache(sess);
+ sess->needs_cache_reconfig = 0;
+ }
+
/*setup authentification*/
strcpy(pass_buf, "");
sess->creds = gf_find_user_credentials_for_site( sess->dm, sess->server_name );
@@ -2619,6 +2676,15 @@ exit:
void http_do_requests(GF_DownloadSession *sess)
{
char sHTTP[GF_DOWNLOAD_BUFFER_SIZE];
+
+ if (sess->reused_cache_entry) {
+ if (!gf_cache_is_in_progress(sess->cache_entry)) {
+ sess->status = GF_NETIO_DISCONNECTED;
+ sess->reused_cache_entry = 0;
+ }
+ return;
+ }
+
switch (sess->status) {
case GF_NETIO_CONNECTED:
http_send_headers(sess, sHTTP);
@@ -2627,6 +2693,21 @@ void http_do_requests(GF_DownloadSession *sess)
wait_for_header_and_parse(sess, sHTTP);
break;
case GF_NETIO_DATA_EXCHANGE:
+ /*session has been reassigned, resend data retrieved in first GET reply to user but don't write to cache*/
+ if (sess->reassigned) {
+
+ if (sess->icy_metaint > 0) {
+ gf_icy_skip_data(sess, sess->icy_metaint, sess->init_data, sess->init_data_size);
+ } else {
+ GF_NETIO_Parameter par;
+ par.msg_type = GF_NETIO_DATA_EXCHANGE;
+ par.error = GF_OK;
+ par.data = sess->init_data;
+ par.size = sess->init_data_size;
+ gf_dm_sess_user_io(sess, &par);
+ }
+ sess->reassigned = 0;
+ }
http_parse_remaining_body(sess, sHTTP);
break;
}
@@ -2932,7 +3013,7 @@ GF_Err gf_dm_sess_reassign(GF_DownloadSession *sess, u32 flags, gf_dm_user_io us
sess->flags = flags;
sess->user_proc = user_io;
sess->usr_cbk = cbk;
-
+ sess->reassigned = sess->init_data ? 1 : 0;
sess->num_retry = SESSION_RETRY_COUNT;
if (sess->status==GF_NETIO_DISCONNECTED)
diff --git a/src/utils/error.c b/src/utils/error.c
index f6c57d1..939d773 100644
--- a/src/utils/error.c
+++ b/src/utils/error.c
@@ -547,7 +547,7 @@ static const u32 gf_crc_table[256] = {
};
GF_EXPORT
-u32 gf_crc_32(char *data, u32 len)
+u32 gf_crc_32(const char *data, u32 len)
{
register u32 i;
u32 crc = 0xffffffff;
diff --git a/src/utils/os_divers.c b/src/utils/os_divers.c
index 7c383fb..3813b0b 100644
--- a/src/utils/os_divers.c
+++ b/src/utils/os_divers.c
@@ -309,7 +309,7 @@ int gettimeofday(struct timeval *tp, struct timezone *tzp)
}
-#if 0
+#if _GPAC_UNUSED
/*
time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds
FILETIME in Win32 is from jan 1, 1601
@@ -406,7 +406,11 @@ GF_Err gf_move_file(const char *fileName, const char *newFileName)
return (MoveFile(fileName, newFileName) == 0 ) ? GF_IO_ERR : GF_OK;
#else
/* success is == 0 */
- return ( rename(fileName, newFileName) == 0) ? GF_OK : GF_IO_ERR;
+ char cmd[1024];
+ if (!fileName || !newFileName)
+ return GF_IO_ERR;
+ snprintf(cmd, sizeof(cmd)-1, "mv %s %s > /dev/null 2>&1", fileName, newFileName);
+ return ( system(cmd) == 0) ? GF_OK : GF_IO_ERR;
#endif
}
@@ -484,8 +488,13 @@ FILE *gf_temp_file_new()
char tmp[MAX_PATH], t_file[100];
FILE *res = tmpfile();
if (res) return res;
+ {
+ u32 err = GetLastError();
+ GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Win32] system failure for tmpfile(): %08x\n", err));
+ }
/*tmpfile() may fail under vista ...*/
- if (!GetEnvironmentVariable("TEMP",tmp,MAX_PATH)) return NULL;
+ if (!GetEnvironmentVariable("TEMP",tmp,MAX_PATH))
+ return NULL;
sprintf(t_file, "\\gpac_%08x.tmp", (u32) tmp);
strcat(tmp, t_file);
return gf_f64_open(tmp, "w+b");
@@ -804,7 +813,13 @@ GF_EXPORT
FILE *gf_f64_open(const char *file_name, const char *mode)
{
#if defined(WIN32)
- return fopen(file_name, mode);
+ FILE *res = fopen(file_name, mode);
+ if (res) return res;
+ if (strchr(mode, 'w') || strchr(mode, 'a')) {
+ u32 err = GetLastError();
+ GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Win32] system failure for file opening of %s in mode %s: %08x\n", file_name, mode, err));
+ }
+ return NULL;
#elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID)
return fopen64(file_name, mode);
#elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN))
@@ -1922,7 +1937,7 @@ GF_GlobalLock * gf_create_PID_file( const char * resourceName )
{
int sz = 100;
char * buf = gf_malloc( sz );
- sz = snprintf(buf, sz, "%ld\n", (long) getpid());
+ sz = snprintf(buf, sz-1, "%ld\n", (long) getpid());
if (write(fd, buf, sz) != sz){
gf_free(buf);
goto exit;
diff --git a/src/utils/os_thread.c b/src/utils/os_thread.c
index 9a1c990..0f7119f 100644
--- a/src/utils/os_thread.c
+++ b/src/utils/os_thread.c
@@ -700,6 +700,7 @@ u32 gf_sema_notify(GF_Semaphore *sm, u32 NbRelease)
return (u32) prevCount;
}
+GF_EXPORT
void gf_sema_wait(GF_Semaphore *sm)
{
#ifdef WIN32
diff --git a/src/utils/sha1.c b/src/utils/sha1.c
index b78cdec..9711a86 100644
--- a/src/utils/sha1.c
+++ b/src/utils/sha1.c
@@ -693,6 +693,16 @@ s32 gf_sha1_file( const char *path, u8 output[20] )
GF_SHA1Context *ctx;
u8 buf[1024];
+ if (!strncmp(path, "gmem://", 7)) {
+ u32 size;
+ u8 *mem_address;
+ if (sscanf(path, "gmem://%d@%p", &size, &mem_address) != 2) {
+ return GF_IO_ERR;
+ }
+ gf_sha1_csum(mem_address, size, output);
+ return 0;
+ }
+
if( ( f = gf_f64_open( path, "rb" ) ) == NULL )
return( 1 );
diff --git a/src/utils/xml_parser.c b/src/utils/xml_parser.c
index 45d742d..09220d4 100644
--- a/src/utils/xml_parser.c
+++ b/src/utils/xml_parser.c
@@ -26,12 +26,17 @@
#include
#include
+
+#ifndef GPAC_DISABLE_ZLIB
/*since 0.2.2, we use zlib for xmt/x3d reading to handle gz files*/
#include
#if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
#pragma comment(lib, "zlib")
#endif
+#else
+#define NO_GZIP
+#endif
static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current);
@@ -1178,6 +1183,40 @@ GF_Err gf_xml_sax_parse_file(GF_SAXParser *parser, const char *fileName, gf_xml_
#endif
unsigned char szLine[6];
+ parser->on_progress = OnProgress;
+
+ if (!strncmp(fileName, "gmem://", 7)) {
+ u32 size;
+ u8 *xml_mem_address;
+ if (sscanf(fileName, "gmem://%d@%p", &size, &xml_mem_address) != 2) {
+ return GF_URL_ERROR;
+ }
+ parser->file_size = size;
+
+ memcpy(szLine, xml_mem_address, 3);
+ szLine[4] = szLine[5] = 0;
+ e = gf_xml_sax_init(parser, szLine);
+ if (e) return e;
+ parser->file_pos = 4;
+ parser->elt_start_pos = 0;
+ parser->current_pos = 0;
+
+
+ e = gf_xml_sax_parse(parser, xml_mem_address+3);
+ if (parser->on_progress) parser->on_progress(parser->sax_cbck, parser->file_pos, parser->file_size);
+
+ parser->elt_start_pos = parser->elt_end_pos = 0;
+ parser->elt_name_start = parser->elt_name_end = 0;
+ parser->att_name_start = 0;
+ parser->current_pos = 0;
+ parser->line_size = 0;
+ parser->att_sep = 0;
+ parser->file_pos = 0;
+ parser->file_size = 0;
+ parser->line_size = 0;
+ return e;
+ }
+
/*check file exists and gets its size (zlib doesn't support SEEK_END)*/
test = gf_f64_open(fileName, "rb");
if (!test) return GF_URL_ERROR;
@@ -1186,7 +1225,6 @@ GF_Err gf_xml_sax_parse_file(GF_SAXParser *parser, const char *fileName, gf_xml_
parser->file_size = (u32) gf_f64_tell(test);
fclose(test);
- parser->on_progress = OnProgress;
#ifdef NO_GZIP
parser->f_in = gf_f64_open(fileName, "rt");
@@ -1294,7 +1332,11 @@ GF_EXPORT
char *gf_xml_sax_peek_node(GF_SAXParser *parser, char *att_name, char *att_value, char *substitute, char *get_attr, char *end_pattern, Bool *is_substitute)
{
u32 state, att_len, alloc_size;
+#ifdef NO_GZIP
+ u64 pos;
+#else
z_off_t pos;
+#endif
Bool from_buffer;
Bool dobreak=0;
char szLine1[XML_INPUT_SIZE+2], szLine2[XML_INPUT_SIZE+2], *szLine, *cur_line, *sep, *start, first_c, *result;