Signed-off-by: Martin Storsjö <martin@martin.st>
Martin Storsjö authored on 2012/01/10 00:58:26... | ... |
@@ -111,6 +111,7 @@ void av_register_all(void) |
111 | 111 |
REGISTER_DEMUXER (INGENIENT, ingenient); |
112 | 112 |
REGISTER_DEMUXER (IPMOVIE, ipmovie); |
113 | 113 |
REGISTER_MUXER (IPOD, ipod); |
114 |
+ REGISTER_MUXER (ISMV, ismv); |
|
114 | 115 |
REGISTER_DEMUXER (ISS, iss); |
115 | 116 |
REGISTER_DEMUXER (IV8, iv8); |
116 | 117 |
REGISTER_MUXDEMUX (IVF, ivf); |
... | ... |
@@ -55,6 +55,7 @@ static const AVOption options[] = { |
55 | 55 |
{ "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.dbl = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM}, |
56 | 56 |
{ "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, |
57 | 57 |
{ "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, |
58 |
+ { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, |
|
58 | 59 |
{ NULL }, |
59 | 60 |
}; |
60 | 61 |
|
... | ... |
@@ -761,7 +762,7 @@ static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track) |
761 | 761 |
{ |
762 | 762 |
int tag = track->enc->codec_tag; |
763 | 763 |
|
764 |
- if (track->mode == MODE_MP4 || track->mode == MODE_PSP) |
|
764 |
+ if (track->mode == MODE_MP4 || track->mode == MODE_PSP || track->mode == MODE_ISM) |
|
765 | 765 |
tag = mp4_get_codec_tag(s, track); |
766 | 766 |
else if (track->mode == MODE_IPOD) |
767 | 767 |
tag = ipod_get_codec_tag(s, track); |
... | ... |
@@ -1940,6 +1941,11 @@ static int mov_write_tfhd_tag(AVIOContext *pb, MOVTrack *track, |
1940 | 1940 |
flags |= 0x20; /* default-sample-flags-present */ |
1941 | 1941 |
} |
1942 | 1942 |
|
1943 |
+ /* Don't set a default sample size when creating data for silverlight, |
|
1944 |
+ * the player refuses to play files with that set. */ |
|
1945 |
+ if (track->mode == MODE_ISM) |
|
1946 |
+ flags &= ~0x10; |
|
1947 |
+ |
|
1943 | 1948 |
avio_wb32(pb, 0); /* size placeholder */ |
1944 | 1949 |
ffio_wfourcc(pb, "tfhd"); |
1945 | 1950 |
avio_w8(pb, 0); /* version */ |
... | ... |
@@ -2023,7 +2029,78 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track) |
2023 | 2023 |
return updateSize(pb, pos); |
2024 | 2024 |
} |
2025 | 2025 |
|
2026 |
-static int mov_write_traf_tag(AVIOContext *pb, MOVTrack *track, int64_t moof_offset) |
|
2026 |
+static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track) |
|
2027 |
+{ |
|
2028 |
+ int64_t pos = avio_tell(pb); |
|
2029 |
+ const uint8_t uuid[] = { |
|
2030 |
+ 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6, |
|
2031 |
+ 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2 |
|
2032 |
+ }; |
|
2033 |
+ |
|
2034 |
+ avio_wb32(pb, 0); /* size placeholder */ |
|
2035 |
+ ffio_wfourcc(pb, "uuid"); |
|
2036 |
+ avio_write(pb, uuid, sizeof(uuid)); |
|
2037 |
+ avio_w8(pb, 1); |
|
2038 |
+ avio_wb24(pb, 0); |
|
2039 |
+ avio_wb64(pb, track->frag_start); |
|
2040 |
+ avio_wb64(pb, track->start_dts + track->trackDuration - |
|
2041 |
+ track->cluster[0].dts); |
|
2042 |
+ |
|
2043 |
+ return updateSize(pb, pos); |
|
2044 |
+} |
|
2045 |
+ |
|
2046 |
+static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov, |
|
2047 |
+ MOVTrack *track, int entry) |
|
2048 |
+{ |
|
2049 |
+ int n = track->nb_frag_info - 1 - entry, i; |
|
2050 |
+ int size = 8 + 16 + 4 + 1 + 16*n; |
|
2051 |
+ const uint8_t uuid[] = { |
|
2052 |
+ 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95, |
|
2053 |
+ 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f |
|
2054 |
+ }; |
|
2055 |
+ |
|
2056 |
+ if (entry < 0) |
|
2057 |
+ return 0; |
|
2058 |
+ |
|
2059 |
+ avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET); |
|
2060 |
+ avio_wb32(pb, size); |
|
2061 |
+ ffio_wfourcc(pb, "uuid"); |
|
2062 |
+ avio_write(pb, uuid, sizeof(uuid)); |
|
2063 |
+ avio_w8(pb, 1); |
|
2064 |
+ avio_wb24(pb, 0); |
|
2065 |
+ avio_w8(pb, n); |
|
2066 |
+ for (i = 0; i < n; i++) { |
|
2067 |
+ int index = entry + 1 + i; |
|
2068 |
+ avio_wb64(pb, track->frag_info[index].time); |
|
2069 |
+ avio_wb64(pb, track->frag_info[index].duration); |
|
2070 |
+ } |
|
2071 |
+ if (n < mov->ism_lookahead) { |
|
2072 |
+ int free_size = 16*(mov->ism_lookahead - n); |
|
2073 |
+ avio_wb32(pb, free_size); |
|
2074 |
+ ffio_wfourcc(pb, "free"); |
|
2075 |
+ for (i = 0; i < free_size - 8; i++) |
|
2076 |
+ avio_w8(pb, 0); |
|
2077 |
+ } |
|
2078 |
+ |
|
2079 |
+ return 0; |
|
2080 |
+} |
|
2081 |
+ |
|
2082 |
+static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov, |
|
2083 |
+ MOVTrack *track) |
|
2084 |
+{ |
|
2085 |
+ int64_t pos = avio_tell(pb); |
|
2086 |
+ int i; |
|
2087 |
+ for (i = 0; i < mov->ism_lookahead; i++) { |
|
2088 |
+ /* Update the tfrf tag for the last ism_lookahead fragments, |
|
2089 |
+ * nb_frag_info - 1 is the next fragment to be written. */ |
|
2090 |
+ mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i); |
|
2091 |
+ } |
|
2092 |
+ avio_seek(pb, pos, SEEK_SET); |
|
2093 |
+ return 0; |
|
2094 |
+} |
|
2095 |
+ |
|
2096 |
+static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov, |
|
2097 |
+ MOVTrack *track, int64_t moof_offset) |
|
2027 | 2098 |
{ |
2028 | 2099 |
int64_t pos = avio_tell(pb); |
2029 | 2100 |
avio_wb32(pb, 0); /* size placeholder */ |
... | ... |
@@ -2031,6 +2108,19 @@ static int mov_write_traf_tag(AVIOContext *pb, MOVTrack *track, int64_t moof_off |
2031 | 2031 |
|
2032 | 2032 |
mov_write_tfhd_tag(pb, track, moof_offset); |
2033 | 2033 |
mov_write_trun_tag(pb, track); |
2034 |
+ if (mov->mode == MODE_ISM) { |
|
2035 |
+ mov_write_tfxd_tag(pb, track); |
|
2036 |
+ |
|
2037 |
+ if (mov->ism_lookahead) { |
|
2038 |
+ int i, size = 16 + 4 + 1 + 16*mov->ism_lookahead; |
|
2039 |
+ |
|
2040 |
+ track->tfrf_offset = avio_tell(pb); |
|
2041 |
+ avio_wb32(pb, 8 + size); |
|
2042 |
+ ffio_wfourcc(pb, "free"); |
|
2043 |
+ for (i = 0; i < size; i++) |
|
2044 |
+ avio_w8(pb, 0); |
|
2045 |
+ } |
|
2046 |
+ } |
|
2034 | 2047 |
|
2035 | 2048 |
return updateSize(pb, pos); |
2036 | 2049 |
} |
... | ... |
@@ -2050,7 +2140,7 @@ static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks) |
2050 | 2050 |
continue; |
2051 | 2051 |
if (!track->entry) |
2052 | 2052 |
continue; |
2053 |
- mov_write_traf_tag(pb, track, pos); |
|
2053 |
+ mov_write_traf_tag(pb, mov, track, pos); |
|
2054 | 2054 |
} |
2055 | 2055 |
|
2056 | 2056 |
end = avio_tell(pb); |
... | ... |
@@ -2158,6 +2248,8 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) |
2158 | 2158 |
ffio_wfourcc(pb, "isom"); |
2159 | 2159 |
else if (mov->mode == MODE_IPOD) |
2160 | 2160 |
ffio_wfourcc(pb, has_video ? "M4V ":"M4A "); |
2161 |
+ else if (mov->mode == MODE_ISM) |
|
2162 |
+ ffio_wfourcc(pb, "isml"); |
|
2161 | 2163 |
else |
2162 | 2164 |
ffio_wfourcc(pb, "qt "); |
2163 | 2165 |
|
... | ... |
@@ -2165,7 +2257,10 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) |
2165 | 2165 |
|
2166 | 2166 |
if(mov->mode == MODE_MOV) |
2167 | 2167 |
ffio_wfourcc(pb, "qt "); |
2168 |
- else{ |
|
2168 |
+ else if (mov->mode == MODE_ISM) { |
|
2169 |
+ ffio_wfourcc(pb, "piff"); |
|
2170 |
+ ffio_wfourcc(pb, "iso2"); |
|
2171 |
+ } else { |
|
2169 | 2172 |
ffio_wfourcc(pb, "isom"); |
2170 | 2173 |
ffio_wfourcc(pb, "iso2"); |
2171 | 2174 |
if(has_h264) |
... | ... |
@@ -2342,8 +2437,11 @@ static int mov_flush_fragment(AVFormatContext *s) |
2342 | 2342 |
info = &track->frag_info[track->nb_frag_info - 1]; |
2343 | 2343 |
info->offset = avio_tell(s->pb); |
2344 | 2344 |
info->time = mov->tracks[i].frag_start; |
2345 |
+ info->duration = duration; |
|
2346 |
+ mov_write_tfrf_tags(s->pb, mov, track); |
|
2345 | 2347 |
|
2346 | 2348 |
mov_write_moof_tag(s->pb, mov, moof_tracks); |
2349 |
+ info->tfrf_offset = track->tfrf_offset; |
|
2347 | 2350 |
mov->fragments++; |
2348 | 2351 |
|
2349 | 2352 |
avio_wb32(s->pb, mdat_size + 8); |
... | ... |
@@ -2571,6 +2669,7 @@ static int mov_write_header(AVFormatContext *s) |
2571 | 2571 |
else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV; |
2572 | 2572 |
else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP; |
2573 | 2573 |
else if (!strcmp("ipod",s->oformat->name)) mov->mode = MODE_IPOD; |
2574 |
+ else if (!strcmp("ismv",s->oformat->name)) mov->mode = MODE_ISM; |
|
2574 | 2575 |
|
2575 | 2576 |
mov_write_ftyp_tag(pb,s); |
2576 | 2577 |
if (mov->mode == MODE_PSP) { |
... | ... |
@@ -2681,6 +2780,10 @@ static int mov_write_header(AVFormatContext *s) |
2681 | 2681 |
} |
2682 | 2682 |
if (!track->height) |
2683 | 2683 |
track->height = st->codec->height; |
2684 |
+ /* The ism specific timescale isn't mandatory, but is assumed by |
|
2685 |
+ * some tools, such as mp4split. */ |
|
2686 |
+ if (mov->mode == MODE_ISM) |
|
2687 |
+ track->timescale = 10000000; |
|
2684 | 2688 |
|
2685 | 2689 |
avpriv_set_pts_info(st, 64, 1, track->timescale); |
2686 | 2690 |
|
... | ... |
@@ -2692,6 +2795,15 @@ static int mov_write_header(AVFormatContext *s) |
2692 | 2692 |
} |
2693 | 2693 |
} |
2694 | 2694 |
|
2695 |
+ if (mov->mode == MODE_ISM) { |
|
2696 |
+ /* If no fragmentation options have been set, set a default. */ |
|
2697 |
+ if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME | |
|
2698 |
+ FF_MOV_FLAG_FRAG_CUSTOM)) && |
|
2699 |
+ !mov->max_fragment_duration && !mov->max_fragment_size) |
|
2700 |
+ mov->max_fragment_duration = 5000000; |
|
2701 |
+ mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF; |
|
2702 |
+ } |
|
2703 |
+ |
|
2695 | 2704 |
/* Set the FRAGMENT flag if any of the fragmentation methods are |
2696 | 2705 |
* enabled. */ |
2697 | 2706 |
if (mov->max_fragment_duration || mov->max_fragment_size || |
... | ... |
@@ -2906,3 +3018,21 @@ AVOutputFormat ff_ipod_muxer = { |
2906 | 2906 |
.priv_class = &ipod_muxer_class, |
2907 | 2907 |
}; |
2908 | 2908 |
#endif |
2909 |
+#if CONFIG_ISMV_MUXER |
|
2910 |
+MOV_CLASS(ismv) |
|
2911 |
+AVOutputFormat ff_ismv_muxer = { |
|
2912 |
+ .name = "ismv", |
|
2913 |
+ .long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming) format"), |
|
2914 |
+ .mime_type = "application/mp4", |
|
2915 |
+ .extensions = "ismv,isma", |
|
2916 |
+ .priv_data_size = sizeof(MOVMuxContext), |
|
2917 |
+ .audio_codec = CODEC_ID_AAC, |
|
2918 |
+ .video_codec = CODEC_ID_H264, |
|
2919 |
+ .write_header = mov_write_header, |
|
2920 |
+ .write_packet = ff_mov_write_packet, |
|
2921 |
+ .write_trailer = mov_write_trailer, |
|
2922 |
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, |
|
2923 |
+ .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0}, |
|
2924 |
+ .priv_class = &ismv_muxer_class, |
|
2925 |
+}; |
|
2926 |
+#endif |
... | ... |
@@ -38,6 +38,7 @@ |
38 | 38 |
// avconv -i testinput.avi -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4 |
39 | 39 |
#define MODE_3G2 0x10 |
40 | 40 |
#define MODE_IPOD 0x20 |
41 |
+#define MODE_ISM 0x40 |
|
41 | 42 |
|
42 | 43 |
typedef struct MOVIentry { |
43 | 44 |
uint64_t pos; |
... | ... |
@@ -68,6 +69,8 @@ typedef struct { |
68 | 68 |
typedef struct { |
69 | 69 |
int64_t offset; |
70 | 70 |
int64_t time; |
71 |
+ int64_t duration; |
|
72 |
+ int64_t tfrf_offset; |
|
71 | 73 |
} MOVFragmentInfo; |
72 | 74 |
|
73 | 75 |
typedef struct MOVIndex { |
... | ... |
@@ -113,6 +116,7 @@ typedef struct MOVIndex { |
113 | 113 |
int64_t moof_size_offset; |
114 | 114 |
int64_t data_offset; |
115 | 115 |
int64_t frag_start; |
116 |
+ int64_t tfrf_offset; |
|
116 | 117 |
|
117 | 118 |
int nb_frag_info; |
118 | 119 |
MOVFragmentInfo *frag_info; |
... | ... |
@@ -137,6 +141,7 @@ typedef struct MOVMuxContext { |
137 | 137 |
int fragments; |
138 | 138 |
int max_fragment_duration; |
139 | 139 |
int max_fragment_size; |
140 |
+ int ism_lookahead; |
|
140 | 141 |
} MOVMuxContext; |
141 | 142 |
|
142 | 143 |
#define FF_MOV_FLAG_RTP_HINT 1 |
... | ... |
@@ -30,7 +30,7 @@ |
30 | 30 |
#include "libavutil/avutil.h" |
31 | 31 |
|
32 | 32 |
#define LIBAVFORMAT_VERSION_MAJOR 53 |
33 |
-#define LIBAVFORMAT_VERSION_MINOR 22 |
|
33 |
+#define LIBAVFORMAT_VERSION_MINOR 23 |
|
34 | 34 |
#define LIBAVFORMAT_VERSION_MICRO 0 |
35 | 35 |
|
36 | 36 |
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |