Mercurial > libavformat.hg
comparison movenc.c @ 6013:332ad5f30c0e libavformat
Add initial support for RTP hinting in the mov muxer
author | mstorsjo |
---|---|
date | Tue, 18 May 2010 19:47:24 +0000 |
parents | 8298cc054242 |
children | 2bab410094e0 |
comparison
equal
deleted
inserted
replaced
6012:8298cc054242 | 6013:332ad5f30c0e |
---|---|
27 #include "avio.h" | 27 #include "avio.h" |
28 #include "isom.h" | 28 #include "isom.h" |
29 #include "avc.h" | 29 #include "avc.h" |
30 #include "libavcodec/get_bits.h" | 30 #include "libavcodec/get_bits.h" |
31 #include "libavcodec/put_bits.h" | 31 #include "libavcodec/put_bits.h" |
32 #include "internal.h" | |
33 #include "libavutil/avstring.h" | |
32 | 34 |
33 #undef NDEBUG | 35 #undef NDEBUG |
34 #include <assert.h> | 36 #include <assert.h> |
35 | 37 |
36 //FIXME support 64 bit variant with wide placeholders | 38 //FIXME support 64 bit variant with wide placeholders |
804 mov_write_glbl_tag(pb, track); | 806 mov_write_glbl_tag(pb, track); |
805 | 807 |
806 return updateSize(pb, pos); | 808 return updateSize(pb, pos); |
807 } | 809 } |
808 | 810 |
811 static int mov_write_rtp_tag(ByteIOContext *pb, MOVTrack *track) | |
812 { | |
813 int64_t pos = url_ftell(pb); | |
814 put_be32(pb, 0); /* size */ | |
815 put_tag(pb, "rtp "); | |
816 put_be32(pb, 0); /* Reserved */ | |
817 put_be16(pb, 0); /* Reserved */ | |
818 put_be16(pb, 1); /* Data-reference index */ | |
819 | |
820 put_be16(pb, 1); /* Hint track version */ | |
821 put_be16(pb, 1); /* Highest compatible version */ | |
822 put_be32(pb, track->max_packet_size); /* Max packet size */ | |
823 | |
824 put_be32(pb, 12); /* size */ | |
825 put_tag(pb, "tims"); | |
826 put_be32(pb, track->timescale); | |
827 | |
828 return updateSize(pb, pos); | |
829 } | |
830 | |
809 static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack *track) | 831 static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack *track) |
810 { | 832 { |
811 int64_t pos = url_ftell(pb); | 833 int64_t pos = url_ftell(pb); |
812 put_be32(pb, 0); /* size */ | 834 put_be32(pb, 0); /* size */ |
813 put_tag(pb, "stsd"); | 835 put_tag(pb, "stsd"); |
817 mov_write_video_tag(pb, track); | 839 mov_write_video_tag(pb, track); |
818 else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) | 840 else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) |
819 mov_write_audio_tag(pb, track); | 841 mov_write_audio_tag(pb, track); |
820 else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) | 842 else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) |
821 mov_write_subtitle_tag(pb, track); | 843 mov_write_subtitle_tag(pb, track); |
844 else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) | |
845 mov_write_rtp_tag(pb, track); | |
822 return updateSize(pb, pos); | 846 return updateSize(pb, pos); |
823 } | 847 } |
824 | 848 |
825 static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack *track) | 849 static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack *track) |
826 { | 850 { |
916 int64_t pos = url_ftell(pb); | 940 int64_t pos = url_ftell(pb); |
917 put_be32(pb, 0); /* size */ | 941 put_be32(pb, 0); /* size */ |
918 put_tag(pb, "stbl"); | 942 put_tag(pb, "stbl"); |
919 mov_write_stsd_tag(pb, track); | 943 mov_write_stsd_tag(pb, track); |
920 mov_write_stts_tag(pb, track); | 944 mov_write_stts_tag(pb, track); |
921 if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO && | 945 if ((track->enc->codec_type == AVMEDIA_TYPE_VIDEO || |
946 track->enc->codec_tag == MKTAG('r','t','p',' ')) && | |
922 track->hasKeyframes && track->hasKeyframes < track->entry) | 947 track->hasKeyframes && track->hasKeyframes < track->entry) |
923 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE); | 948 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE); |
924 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS) | 949 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS) |
925 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE); | 950 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE); |
926 if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO && | 951 if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO && |
1003 descr = "SoundHandler"; | 1028 descr = "SoundHandler"; |
1004 } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { | 1029 } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { |
1005 if (track->tag == MKTAG('t','x','3','g')) hdlr_type = "sbtl"; | 1030 if (track->tag == MKTAG('t','x','3','g')) hdlr_type = "sbtl"; |
1006 else hdlr_type = "text"; | 1031 else hdlr_type = "text"; |
1007 descr = "SubtitleHandler"; | 1032 descr = "SubtitleHandler"; |
1033 } else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) { | |
1034 hdlr_type = "hint"; | |
1035 descr = "HintHandler"; | |
1008 } | 1036 } |
1009 } | 1037 } |
1010 | 1038 |
1011 put_be32(pb, 0); /* size */ | 1039 put_be32(pb, 0); /* size */ |
1012 put_tag(pb, "hdlr"); | 1040 put_tag(pb, "hdlr"); |
1022 if (track && track->mode != MODE_MOV) | 1050 if (track && track->mode != MODE_MOV) |
1023 put_byte(pb, 0); /* c string */ | 1051 put_byte(pb, 0); /* c string */ |
1024 return updateSize(pb, pos); | 1052 return updateSize(pb, pos); |
1025 } | 1053 } |
1026 | 1054 |
1055 static int mov_write_hmhd_tag(ByteIOContext *pb) | |
1056 { | |
1057 /* This atom must be present, but leaving the values at zero | |
1058 * seems harmless. */ | |
1059 put_be32(pb, 28); /* size */ | |
1060 put_tag(pb, "hmhd"); | |
1061 put_be32(pb, 0); /* version, flags */ | |
1062 put_be16(pb, 0); /* maxPDUsize */ | |
1063 put_be16(pb, 0); /* avgPDUsize */ | |
1064 put_be32(pb, 0); /* maxbitrate */ | |
1065 put_be32(pb, 0); /* avgbitrate */ | |
1066 put_be32(pb, 0); /* reserved */ | |
1067 return 28; | |
1068 } | |
1069 | |
1027 static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack *track) | 1070 static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack *track) |
1028 { | 1071 { |
1029 int64_t pos = url_ftell(pb); | 1072 int64_t pos = url_ftell(pb); |
1030 put_be32(pb, 0); /* size */ | 1073 put_be32(pb, 0); /* size */ |
1031 put_tag(pb, "minf"); | 1074 put_tag(pb, "minf"); |
1034 else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) | 1077 else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) |
1035 mov_write_smhd_tag(pb); | 1078 mov_write_smhd_tag(pb); |
1036 else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { | 1079 else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { |
1037 if (track->tag == MKTAG('t','e','x','t')) mov_write_gmhd_tag(pb); | 1080 if (track->tag == MKTAG('t','e','x','t')) mov_write_gmhd_tag(pb); |
1038 else mov_write_nmhd_tag(pb); | 1081 else mov_write_nmhd_tag(pb); |
1082 } else if (track->tag == MKTAG('r','t','p',' ')) { | |
1083 mov_write_hmhd_tag(pb); | |
1039 } | 1084 } |
1040 if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */ | 1085 if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */ |
1041 mov_write_hdlr_tag(pb, NULL); | 1086 mov_write_hdlr_tag(pb, NULL); |
1042 mov_write_dinf_tag(pb); | 1087 mov_write_dinf_tag(pb); |
1043 mov_write_stbl_tag(pb, track); | 1088 mov_write_stbl_tag(pb, track); |
1189 put_be32(pb, 0x1); | 1234 put_be32(pb, 0x1); |
1190 put_be32(pb, 0x0); | 1235 put_be32(pb, 0x0); |
1191 return 0x34; | 1236 return 0x34; |
1192 } | 1237 } |
1193 | 1238 |
1239 static int mov_write_udta_sdp(ByteIOContext *pb, AVCodecContext *ctx, int index) | |
1240 { | |
1241 char buf[1000] = ""; | |
1242 int len; | |
1243 | |
1244 ff_sdp_write_media(buf, sizeof(buf), ctx, NULL, 0, 0); | |
1245 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", index); | |
1246 len = strlen(buf); | |
1247 | |
1248 put_be32(pb, len + 24); | |
1249 put_tag (pb, "udta"); | |
1250 put_be32(pb, len + 16); | |
1251 put_tag (pb, "hnti"); | |
1252 put_be32(pb, len + 8); | |
1253 put_tag (pb, "sdp "); | |
1254 put_buffer(pb, buf, len); | |
1255 return len + 24; | |
1256 } | |
1257 | |
1194 static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack *track, AVStream *st) | 1258 static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack *track, AVStream *st) |
1195 { | 1259 { |
1196 int64_t pos = url_ftell(pb); | 1260 int64_t pos = url_ftell(pb); |
1197 put_be32(pb, 0); /* size */ | 1261 put_be32(pb, 0); /* size */ |
1198 put_tag(pb, "trak"); | 1262 put_tag(pb, "trak"); |
1202 if (track->tref_tag) | 1266 if (track->tref_tag) |
1203 mov_write_tref_tag(pb, track); | 1267 mov_write_tref_tag(pb, track); |
1204 mov_write_mdia_tag(pb, track); | 1268 mov_write_mdia_tag(pb, track); |
1205 if (track->mode == MODE_PSP) | 1269 if (track->mode == MODE_PSP) |
1206 mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box | 1270 mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box |
1271 if (track->tag == MKTAG('r','t','p',' ')) | |
1272 mov_write_udta_sdp(pb, track->rtp_ctx->streams[0]->codec, track->trackID); | |
1207 return updateSize(pb, pos); | 1273 return updateSize(pb, pos); |
1208 } | 1274 } |
1209 | 1275 |
1210 #if 0 | 1276 #if 0 |
1211 /* TODO: Not sorted out, but not necessary either */ | 1277 /* TODO: Not sorted out, but not necessary either */ |
1616 if (mov->chapter_track) | 1682 if (mov->chapter_track) |
1617 for (i=0; i<s->nb_streams; i++) { | 1683 for (i=0; i<s->nb_streams; i++) { |
1618 mov->tracks[i].tref_tag = MKTAG('c','h','a','p'); | 1684 mov->tracks[i].tref_tag = MKTAG('c','h','a','p'); |
1619 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].trackID; | 1685 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].trackID; |
1620 } | 1686 } |
1687 for (i = 0; i < mov->nb_streams; i++) { | |
1688 if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) { | |
1689 mov->tracks[i].tref_tag = MKTAG('h','i','n','t'); | |
1690 mov->tracks[i].tref_id = | |
1691 mov->tracks[mov->tracks[i].src_track].trackID; | |
1692 } | |
1693 } | |
1621 | 1694 |
1622 mov_write_mvhd_tag(pb, mov); | 1695 mov_write_mvhd_tag(pb, mov); |
1623 //mov_write_iods_tag(pb, mov); | 1696 //mov_write_iods_tag(pb, mov); |
1624 for (i=0; i<mov->nb_streams; i++) { | 1697 for (i=0; i<mov->nb_streams; i++) { |
1625 if(mov->tracks[i].entry > 0) { | 1698 if(mov->tracks[i].entry > 0) { |
1876 trk->entry++; | 1949 trk->entry++; |
1877 trk->sampleCount += samplesInChunk; | 1950 trk->sampleCount += samplesInChunk; |
1878 mov->mdat_size += size; | 1951 mov->mdat_size += size; |
1879 | 1952 |
1880 put_flush_packet(pb); | 1953 put_flush_packet(pb); |
1954 | |
1955 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) | |
1956 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry); | |
1881 return 0; | 1957 return 0; |
1882 } | 1958 } |
1883 | 1959 |
1884 // QuickTime chapters involve an additional text track with the chapter names | 1960 // QuickTime chapters involve an additional text track with the chapter names |
1885 // as samples, and a tref pointing from the other tracks to the chapter one. | 1961 // as samples, and a tref pointing from the other tracks to the chapter one. |
1918 | 1994 |
1919 static int mov_write_header(AVFormatContext *s) | 1995 static int mov_write_header(AVFormatContext *s) |
1920 { | 1996 { |
1921 ByteIOContext *pb = s->pb; | 1997 ByteIOContext *pb = s->pb; |
1922 MOVMuxContext *mov = s->priv_data; | 1998 MOVMuxContext *mov = s->priv_data; |
1923 int i; | 1999 int i, hint_track = 0; |
1924 | 2000 |
1925 if (url_is_streamed(s->pb)) { | 2001 if (url_is_streamed(s->pb)) { |
1926 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n"); | 2002 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n"); |
1927 return -1; | 2003 return -1; |
1928 } | 2004 } |
1948 } | 2024 } |
1949 | 2025 |
1950 mov->nb_streams = s->nb_streams; | 2026 mov->nb_streams = s->nb_streams; |
1951 if (mov->mode & (MODE_MOV|MODE_IPOD) && s->nb_chapters) | 2027 if (mov->mode & (MODE_MOV|MODE_IPOD) && s->nb_chapters) |
1952 mov->chapter_track = mov->nb_streams++; | 2028 mov->chapter_track = mov->nb_streams++; |
2029 | |
2030 if (s->flags & AVFMT_FLAG_RTP_HINT) { | |
2031 /* Add hint tracks for each audio and video stream */ | |
2032 hint_track = mov->nb_streams; | |
2033 for (i = 0; i < s->nb_streams; i++) { | |
2034 AVStream *st = s->streams[i]; | |
2035 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || | |
2036 st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { | |
2037 mov->nb_streams++; | |
2038 } | |
2039 } | |
2040 } | |
1953 | 2041 |
1954 mov->tracks = av_mallocz(mov->nb_streams*sizeof(*mov->tracks)); | 2042 mov->tracks = av_mallocz(mov->nb_streams*sizeof(*mov->tracks)); |
1955 if (!mov->tracks) | 2043 if (!mov->tracks) |
1956 return AVERROR(ENOMEM); | 2044 return AVERROR(ENOMEM); |
1957 | 2045 |
1969 if (!track->tag) { | 2057 if (!track->tag) { |
1970 av_log(s, AV_LOG_ERROR, "track %d: could not find tag, " | 2058 av_log(s, AV_LOG_ERROR, "track %d: could not find tag, " |
1971 "codec not currently supported in container\n", i); | 2059 "codec not currently supported in container\n", i); |
1972 goto error; | 2060 goto error; |
1973 } | 2061 } |
2062 /* If hinting of this track is enabled by a later hint track, | |
2063 * this is updated. */ | |
2064 track->hint_track = -1; | |
1974 if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){ | 2065 if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){ |
1975 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') || | 2066 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') || |
1976 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') || | 2067 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') || |
1977 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) { | 2068 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) { |
1978 if (st->codec->width != 720 || (st->codec->height != 608 && st->codec->height != 512)) { | 2069 if (st->codec->width != 720 || (st->codec->height != 608 && st->codec->height != 512)) { |
2023 mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based | 2114 mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based |
2024 | 2115 |
2025 if (mov->chapter_track) | 2116 if (mov->chapter_track) |
2026 mov_create_chapter_track(s, mov->chapter_track); | 2117 mov_create_chapter_track(s, mov->chapter_track); |
2027 | 2118 |
2119 if (s->flags & AVFMT_FLAG_RTP_HINT) { | |
2120 /* Initialize the hint tracks for each audio and video stream */ | |
2121 for (i = 0; i < s->nb_streams; i++) { | |
2122 AVStream *st = s->streams[i]; | |
2123 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || | |
2124 st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { | |
2125 ff_mov_init_hinting(s, hint_track, i); | |
2126 hint_track++; | |
2127 } | |
2128 } | |
2129 } | |
2130 | |
2028 put_flush_packet(pb); | 2131 put_flush_packet(pb); |
2029 | 2132 |
2030 return 0; | 2133 return 0; |
2031 error: | 2134 error: |
2032 av_freep(&mov->tracks); | 2135 av_freep(&mov->tracks); |
2059 | 2162 |
2060 if (mov->chapter_track) | 2163 if (mov->chapter_track) |
2061 av_freep(&mov->tracks[mov->chapter_track].enc); | 2164 av_freep(&mov->tracks[mov->chapter_track].enc); |
2062 | 2165 |
2063 for (i=0; i<mov->nb_streams; i++) { | 2166 for (i=0; i<mov->nb_streams; i++) { |
2167 if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) | |
2168 ff_mov_close_hinting(&mov->tracks[i]); | |
2064 av_freep(&mov->tracks[i].cluster); | 2169 av_freep(&mov->tracks[i].cluster); |
2065 | 2170 |
2066 if(mov->tracks[i].vosLen) av_free(mov->tracks[i].vosData); | 2171 if(mov->tracks[i].vosLen) av_free(mov->tracks[i].vosData); |
2067 | 2172 |
2068 } | 2173 } |