Mercurial > libavformat.hg
comparison movenc.c @ 5993:51b194d7393f libavformat
movenc: Write QuickTime chapters
author | conrad |
---|---|
date | Wed, 05 May 2010 08:41:10 +0000 |
parents | 391e3ca10474 |
children | 97fdefab56cd |
comparison
equal
deleted
inserted
replaced
5992:391e3ca10474 | 5993:51b194d7393f |
---|---|
75 int vosLen; | 75 int vosLen; |
76 uint8_t *vosData; | 76 uint8_t *vosData; |
77 MOVIentry *cluster; | 77 MOVIentry *cluster; |
78 int audio_vbr; | 78 int audio_vbr; |
79 int height; ///< active picture (w/o VBI) height for D-10/IMX | 79 int height; ///< active picture (w/o VBI) height for D-10/IMX |
80 uint32_t tref_tag; | |
81 int tref_id; ///< trackID of the referenced track | |
80 } MOVTrack; | 82 } MOVTrack; |
81 | 83 |
82 typedef struct MOVMuxContext { | 84 typedef struct MOVMuxContext { |
83 int mode; | 85 int mode; |
84 int64_t time; | 86 int64_t time; |
85 int nb_streams; | 87 int nb_streams; |
88 int chapter_track; ///< qt chapter track number | |
86 int64_t mdat_pos; | 89 int64_t mdat_pos; |
87 uint64_t mdat_size; | 90 uint64_t mdat_size; |
88 MOVTrack *tracks; | 91 MOVTrack *tracks; |
89 } MOVMuxContext; | 92 } MOVMuxContext; |
90 | 93 |
1181 put_be32(pb, 0x0); /* reserved */ | 1184 put_be32(pb, 0x0); /* reserved */ |
1182 put_be32(pb, 0x0); /* reserved */ | 1185 put_be32(pb, 0x0); /* reserved */ |
1183 put_be32(pb, 0x40000000); /* reserved */ | 1186 put_be32(pb, 0x40000000); /* reserved */ |
1184 | 1187 |
1185 /* Track width and height, for visual only */ | 1188 /* Track width and height, for visual only */ |
1186 if(track->enc->codec_type == AVMEDIA_TYPE_VIDEO || | 1189 if(st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO || |
1187 track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { | 1190 track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) { |
1188 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); | 1191 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); |
1189 if(!sample_aspect_ratio || track->height != track->enc->height) | 1192 if(!sample_aspect_ratio || track->height != track->enc->height) |
1190 sample_aspect_ratio = 1; | 1193 sample_aspect_ratio = 1; |
1191 put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000); | 1194 put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000); |
1192 put_be32(pb, track->height*0x10000); | 1195 put_be32(pb, track->height*0x10000); |
1213 track->timescale, AV_ROUND_UP)); | 1216 track->timescale, AV_ROUND_UP)); |
1214 | 1217 |
1215 put_be32(pb, track->cluster[0].cts); /* first pts is cts since dts is 0 */ | 1218 put_be32(pb, track->cluster[0].cts); /* first pts is cts since dts is 0 */ |
1216 put_be32(pb, 0x00010000); | 1219 put_be32(pb, 0x00010000); |
1217 return 0x24; | 1220 return 0x24; |
1221 } | |
1222 | |
1223 static int mov_write_tref_tag(ByteIOContext *pb, MOVTrack *track) | |
1224 { | |
1225 put_be32(pb, 20); // size | |
1226 put_tag(pb, "tref"); | |
1227 put_be32(pb, 12); // size (subatom) | |
1228 put_le32(pb, track->tref_tag); | |
1229 put_be32(pb, track->tref_id); | |
1230 return 20; | |
1218 } | 1231 } |
1219 | 1232 |
1220 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it) | 1233 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it) |
1221 static int mov_write_uuid_tag_psp(ByteIOContext *pb, MOVTrack *mov) | 1234 static int mov_write_uuid_tag_psp(ByteIOContext *pb, MOVTrack *mov) |
1222 { | 1235 { |
1242 put_be32(pb, 0); /* size */ | 1255 put_be32(pb, 0); /* size */ |
1243 put_tag(pb, "trak"); | 1256 put_tag(pb, "trak"); |
1244 mov_write_tkhd_tag(pb, track, st); | 1257 mov_write_tkhd_tag(pb, track, st); |
1245 if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS) | 1258 if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS) |
1246 mov_write_edts_tag(pb, track); // PSP Movies require edts box | 1259 mov_write_edts_tag(pb, track); // PSP Movies require edts box |
1260 if (track->tref_tag) | |
1261 mov_write_tref_tag(pb, track); | |
1247 mov_write_mdia_tag(pb, track); | 1262 mov_write_mdia_tag(pb, track); |
1248 if (track->mode == MODE_PSP) | 1263 if (track->mode == MODE_PSP) |
1249 mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box | 1264 mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box |
1250 return updateSize(pb, pos); | 1265 return updateSize(pb, pos); |
1251 } | 1266 } |
1654 | 1669 |
1655 mov->tracks[i].time = mov->time; | 1670 mov->tracks[i].time = mov->time; |
1656 mov->tracks[i].trackID = i+1; | 1671 mov->tracks[i].trackID = i+1; |
1657 } | 1672 } |
1658 | 1673 |
1674 if (mov->chapter_track) | |
1675 for (i=0; i<s->nb_streams; i++) { | |
1676 mov->tracks[i].tref_tag = MKTAG('c','h','a','p'); | |
1677 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].trackID; | |
1678 } | |
1679 | |
1659 mov_write_mvhd_tag(pb, mov); | 1680 mov_write_mvhd_tag(pb, mov); |
1660 //mov_write_iods_tag(pb, mov); | 1681 //mov_write_iods_tag(pb, mov); |
1661 for (i=0; i<mov->nb_streams; i++) { | 1682 for (i=0; i<mov->nb_streams; i++) { |
1662 if(mov->tracks[i].entry > 0) { | 1683 if(mov->tracks[i].entry > 0) { |
1663 mov_write_trak_tag(pb, &(mov->tracks[i]), s->streams[i]); | 1684 mov_write_trak_tag(pb, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL); |
1664 } | 1685 } |
1665 } | 1686 } |
1666 | 1687 |
1667 if (mov->mode == MODE_PSP) | 1688 if (mov->mode == MODE_PSP) |
1668 mov_write_uuidusmt_tag(pb, s); | 1689 mov_write_uuidusmt_tag(pb, s); |
1916 | 1937 |
1917 put_flush_packet(pb); | 1938 put_flush_packet(pb); |
1918 return 0; | 1939 return 0; |
1919 } | 1940 } |
1920 | 1941 |
1942 // QuickTime chapters involve an additional text track with the chapter names | |
1943 // as samples, and a tref pointing from the other tracks to the chapter one. | |
1944 static void mov_create_chapter_track(AVFormatContext *s, int tracknum) | |
1945 { | |
1946 MOVMuxContext *mov = s->priv_data; | |
1947 MOVTrack *track = &mov->tracks[tracknum]; | |
1948 AVPacket pkt = { .stream_index = tracknum, .flags = AV_PKT_FLAG_KEY }; | |
1949 int i, len; | |
1950 | |
1951 track->mode = mov->mode; | |
1952 track->tag = MKTAG('t','e','x','t'); | |
1953 track->timescale = MOV_TIMESCALE; | |
1954 track->enc = avcodec_alloc_context(); | |
1955 track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE; | |
1956 | |
1957 for (i = 0; i < s->nb_chapters; i++) { | |
1958 AVChapter *c = s->chapters[i]; | |
1959 AVMetadataTag *t; | |
1960 | |
1961 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,MOV_TIMESCALE}); | |
1962 pkt.pts = pkt.dts = av_rescale_q(c->start, c->time_base, (AVRational){1,MOV_TIMESCALE}); | |
1963 pkt.duration = end - pkt.dts; | |
1964 | |
1965 if ((t = av_metadata_get(c->metadata, "title", NULL, 0))) { | |
1966 len = strlen(t->value); | |
1967 pkt.size = len+2; | |
1968 pkt.data = av_malloc(pkt.size); | |
1969 AV_WB16(pkt.data, len); | |
1970 memcpy(pkt.data+2, t->value, len); | |
1971 mov_write_packet(s, &pkt); | |
1972 av_freep(&pkt.data); | |
1973 } | |
1974 } | |
1975 } | |
1976 | |
1921 static int mov_write_header(AVFormatContext *s) | 1977 static int mov_write_header(AVFormatContext *s) |
1922 { | 1978 { |
1923 ByteIOContext *pb = s->pb; | 1979 ByteIOContext *pb = s->pb; |
1924 MOVMuxContext *mov = s->priv_data; | 1980 MOVMuxContext *mov = s->priv_data; |
1925 int i; | 1981 int i; |
1947 } | 2003 } |
1948 mov_write_uuidprof_tag(pb,s); | 2004 mov_write_uuidprof_tag(pb,s); |
1949 } | 2005 } |
1950 } | 2006 } |
1951 | 2007 |
1952 mov->tracks = av_mallocz(s->nb_streams*sizeof(*mov->tracks)); | 2008 mov->nb_streams = s->nb_streams; |
2009 if (mov->mode & (MODE_MOV|MODE_IPOD) && s->nb_chapters) | |
2010 mov->chapter_track = mov->nb_streams++; | |
2011 | |
2012 mov->tracks = av_mallocz(mov->nb_streams*sizeof(*mov->tracks)); | |
1953 if (!mov->tracks) | 2013 if (!mov->tracks) |
1954 return AVERROR(ENOMEM); | 2014 return AVERROR(ENOMEM); |
1955 | 2015 |
1956 for(i=0; i<s->nb_streams; i++){ | 2016 for(i=0; i<s->nb_streams; i++){ |
1957 AVStream *st= s->streams[i]; | 2017 AVStream *st= s->streams[i]; |
2017 av_set_pts_info(st, 64, 1, track->timescale); | 2077 av_set_pts_info(st, 64, 1, track->timescale); |
2018 } | 2078 } |
2019 | 2079 |
2020 mov_write_mdat_tag(pb, mov); | 2080 mov_write_mdat_tag(pb, mov); |
2021 mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based | 2081 mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based |
2022 mov->nb_streams = s->nb_streams; | 2082 |
2083 if (mov->chapter_track) | |
2084 mov_create_chapter_track(s, mov->chapter_track); | |
2023 | 2085 |
2024 put_flush_packet(pb); | 2086 put_flush_packet(pb); |
2025 | 2087 |
2026 return 0; | 2088 return 0; |
2027 error: | 2089 error: |
2050 put_be64(pb, mov->mdat_size+16); | 2112 put_be64(pb, mov->mdat_size+16); |
2051 } | 2113 } |
2052 url_fseek(pb, moov_pos, SEEK_SET); | 2114 url_fseek(pb, moov_pos, SEEK_SET); |
2053 | 2115 |
2054 mov_write_moov_tag(pb, mov, s); | 2116 mov_write_moov_tag(pb, mov, s); |
2117 | |
2118 if (mov->chapter_track) | |
2119 av_freep(&mov->tracks[mov->chapter_track].enc); | |
2055 | 2120 |
2056 for (i=0; i<mov->nb_streams; i++) { | 2121 for (i=0; i<mov->nb_streams; i++) { |
2057 av_freep(&mov->tracks[i].cluster); | 2122 av_freep(&mov->tracks[i].cluster); |
2058 | 2123 |
2059 if(mov->tracks[i].vosLen) av_free(mov->tracks[i].vosData); | 2124 if(mov->tracks[i].vosLen) av_free(mov->tracks[i].vosData); |