Mercurial > libavformat.hg
annotate avienc.c @ 4723:a2390c6a35e6 libavformat
Fix index generation in the way that it was supposed to be used. See the
discussion in the ML thread "[PATCH] rmdec.c: merge old/new packet reading
code".
Over time, this code broke somewhat, e.g. seq was never actually written
into (and was thus always 1, therefore the seq condition was always true),
whereas it was supposed to be set to the sequence number of the video slice
in case the video frame is divided over multiple RM packets (slices). The
problem of this is that packets other than those containing the beginning
of a video frame would be indexed as well.
Secondly, flags&2 is supposed to be true for video keyframes and for these
audio packets containing the start of a block. For some codecs (e.g. AAC),
that is every single packet, whereas for others (e.g. cook), that is the
packet containing the first of a series of scrambled packets that are to be
descrambled together. Indexing any of the following would lead to incomplete
and thus useless frames. Problem here is that flags would be reset to 2 to
indicate that the first packet is ready to be returned, and in addition if
no data was left to be returned (which is always true for the first packet),
then we wouldn't actually write the index entry anyway.
All in all, the idea was good and it probably worked at some point, but that
is long ago. This patch should at the very least make it likely for this code
to be executed again at the right times, i.e. the way it was originally
intended to be used.
author | rbultje |
---|---|
date | Sun, 15 Mar 2009 20:14:25 +0000 |
parents | 963e3b76c7a6 |
children | 5748ec2d6705 |
rev | line source |
---|---|
0 | 1 /* |
1415
3b00fb8ef8e4
replace coder/decoder file description in libavformat by muxer/demuxer
aurel
parents:
1358
diff
changeset
|
2 * AVI muxer |
4251
77e0c7511d41
cosmetics: Remove pointless period after copyright statement non-sentences.
diego
parents:
4250
diff
changeset
|
3 * Copyright (c) 2000 Fabrice Bellard |
0 | 4 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
0 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
0 | 11 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
0 | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
894
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 20 */ |
21 #include "avformat.h" | |
22 #include "avi.h" | |
1172
6a5e58d2114b
move common stuff from avienc.c and wav.c to new file riff.c
mru
parents:
1169
diff
changeset
|
23 #include "riff.h" |
0 | 24 |
25 /* | |
885 | 26 * TODO: |
0 | 27 * - fill all fields if non streamed (nb_frames for example) |
28 */ | |
29 | |
119 | 30 typedef struct AVIIentry { |
31 unsigned int flags, pos, len; | |
32 } AVIIentry; | |
33 | |
34 #define AVI_INDEX_CLUSTER_SIZE 16384 | |
35 | |
0 | 36 typedef struct AVIIndex { |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
37 int64_t indx_start; |
119 | 38 int entry; |
39 int ents_allocated; | |
40 AVIIentry** cluster; | |
0 | 41 } AVIIndex; |
42 | |
43 typedef struct { | |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
44 int64_t riff_start, movi_list, odml_list; |
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
45 int64_t frames_hdr_all, frames_hdr_strm[MAX_STREAMS]; |
0 | 46 int audio_strm_length[MAX_STREAMS]; |
119 | 47 int riff_id; |
479 | 48 int packet_count[MAX_STREAMS]; |
119 | 49 |
50 AVIIndex indexes[MAX_STREAMS]; | |
0 | 51 } AVIContext; |
52 | |
885 | 53 static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id) |
119 | 54 { |
55 int cl = ent_id / AVI_INDEX_CLUSTER_SIZE; | |
56 int id = ent_id % AVI_INDEX_CLUSTER_SIZE; | |
57 return &idx->cluster[cl][id]; | |
58 } | |
59 | |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
60 static int64_t avi_start_new_riff(AVIContext *avi, ByteIOContext *pb, |
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
61 const char* riff_tag, const char* list_tag) |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
62 { |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
63 int64_t loff; |
119 | 64 int i; |
885 | 65 |
119 | 66 avi->riff_id++; |
67 for (i=0; i<MAX_STREAMS; i++) | |
68 avi->indexes[i].entry = 0; | |
885 | 69 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
70 avi->riff_start = start_tag(pb, "RIFF"); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
71 put_tag(pb, riff_tag); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
72 loff = start_tag(pb, "LIST"); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
73 put_tag(pb, list_tag); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
74 return loff; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
75 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
76 |
1332 | 77 static char* avi_stream2fourcc(char* tag, int index, enum CodecType type) |
119 | 78 { |
79 tag[0] = '0'; | |
80 tag[1] = '0' + index; | |
81 if (type == CODEC_TYPE_VIDEO) { | |
82 tag[2] = 'd'; | |
83 tag[3] = 'c'; | |
84 } else { | |
85 tag[2] = 'w'; | |
86 tag[3] = 'b'; | |
87 } | |
88 tag[4] = '\0'; | |
89 return tag; | |
90 } | |
91 | |
1256 | 92 static void avi_write_info_tag(ByteIOContext *pb, const char *tag, const char *str) |
93 { | |
94 int len = strlen(str); | |
95 if (len > 0) { | |
96 len++; | |
97 put_tag(pb, tag); | |
98 put_le32(pb, len); | |
99 put_strz(pb, str); | |
100 if (len & 1) | |
101 put_byte(pb, 0); | |
102 } | |
103 } | |
104 | |
4149 | 105 static void avi_write_info_tag2(AVFormatContext *s, const char *fourcc, const char *key1, const char *key2) |
106 { | |
4250
2fc899894f5e
replace AV_METADATA_IGNORE_CASE flag by a new AV_METADATA_MATCH_CASE flag
aurel
parents:
4206
diff
changeset
|
107 AVMetadataTag *tag= av_metadata_get(s->metadata, key1, NULL, 0); |
4149 | 108 if(!tag && key2) |
4250
2fc899894f5e
replace AV_METADATA_IGNORE_CASE flag by a new AV_METADATA_MATCH_CASE flag
aurel
parents:
4206
diff
changeset
|
109 tag= av_metadata_get(s->metadata, key2, NULL, 0); |
4149 | 110 if(tag) |
111 avi_write_info_tag(s->pb, fourcc, tag->value); | |
112 } | |
113 | |
1267 | 114 static int avi_write_counters(AVFormatContext* s, int riff_id) |
115 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
116 ByteIOContext *pb = s->pb; |
1267 | 117 AVIContext *avi = s->priv_data; |
118 int n, au_byterate, au_ssize, au_scale, nb_frames = 0; | |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
119 int64_t file_size; |
1267 | 120 AVCodecContext* stream; |
121 | |
122 file_size = url_ftell(pb); | |
123 for(n = 0; n < s->nb_streams; n++) { | |
124 assert(avi->frames_hdr_strm[n]); | |
125 stream = s->streams[n]->codec; | |
126 url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET); | |
127 ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); | |
128 if(au_ssize == 0) { | |
129 put_le32(pb, avi->packet_count[n]); | |
130 } else { | |
131 put_le32(pb, avi->audio_strm_length[n] / au_ssize); | |
132 } | |
133 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
134 nb_frames = FFMAX(nb_frames, avi->packet_count[n]); | |
135 } | |
136 if(riff_id == 1) { | |
137 assert(avi->frames_hdr_all); | |
138 url_fseek(pb, avi->frames_hdr_all, SEEK_SET); | |
139 put_le32(pb, nb_frames); | |
140 } | |
141 url_fseek(pb, file_size, SEEK_SET); | |
142 | |
143 return 0; | |
144 } | |
145 | |
0 | 146 static int avi_write_header(AVFormatContext *s) |
147 { | |
148 AVIContext *avi = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
149 ByteIOContext *pb = s->pb; |
0 | 150 int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; |
151 AVCodecContext *stream, *video_enc; | |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
152 int64_t list1, list2, strh, strf; |
0 | 153 |
154 /* header list */ | |
119 | 155 avi->riff_id = 0; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
156 list1 = avi_start_new_riff(avi, pb, "AVI ", "hdrl"); |
0 | 157 |
158 /* avi header */ | |
159 put_tag(pb, "avih"); | |
160 put_le32(pb, 14 * 4); | |
161 bitrate = 0; | |
162 | |
163 video_enc = NULL; | |
164 for(n=0;n<s->nb_streams;n++) { | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
796
diff
changeset
|
165 stream = s->streams[n]->codec; |
0 | 166 bitrate += stream->bit_rate; |
167 if (stream->codec_type == CODEC_TYPE_VIDEO) | |
168 video_enc = stream; | |
169 } | |
885 | 170 |
0 | 171 nb_frames = 0; |
172 | |
36
1188ad85857a
audio only avi patch by (Andriy Rysin <arysin at bcsii dot net>)
michaelni
parents:
15
diff
changeset
|
173 if(video_enc){ |
1556 | 174 put_le32(pb, (uint32_t)(INT64_C(1000000) * video_enc->time_base.num / video_enc->time_base.den)); |
36
1188ad85857a
audio only avi patch by (Andriy Rysin <arysin at bcsii dot net>)
michaelni
parents:
15
diff
changeset
|
175 } else { |
887 | 176 put_le32(pb, 0); |
36
1188ad85857a
audio only avi patch by (Andriy Rysin <arysin at bcsii dot net>)
michaelni
parents:
15
diff
changeset
|
177 } |
0 | 178 put_le32(pb, bitrate / 8); /* XXX: not quite exact */ |
179 put_le32(pb, 0); /* padding */ | |
873
7af647503b67
Support for streaming: dont write indexes and dont signal HAS_INDEX in header. Also set filesize to max in this case.
alex
parents:
863
diff
changeset
|
180 if (url_is_streamed(pb)) |
887 | 181 put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ |
873
7af647503b67
Support for streaming: dont write indexes and dont signal HAS_INDEX in header. Also set filesize to max in this case.
alex
parents:
863
diff
changeset
|
182 else |
887 | 183 put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ |
0 | 184 avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */ |
185 put_le32(pb, nb_frames); /* nb frames, filled later */ | |
186 put_le32(pb, 0); /* initial frame */ | |
187 put_le32(pb, s->nb_streams); /* nb streams */ | |
188 put_le32(pb, 1024 * 1024); /* suggested buffer size */ | |
885 | 189 if(video_enc){ |
992 | 190 put_le32(pb, video_enc->width); |
191 put_le32(pb, video_enc->height); | |
36
1188ad85857a
audio only avi patch by (Andriy Rysin <arysin at bcsii dot net>)
michaelni
parents:
15
diff
changeset
|
192 } else { |
887 | 193 put_le32(pb, 0); |
194 put_le32(pb, 0); | |
885 | 195 } |
0 | 196 put_le32(pb, 0); /* reserved */ |
197 put_le32(pb, 0); /* reserved */ | |
198 put_le32(pb, 0); /* reserved */ | |
199 put_le32(pb, 0); /* reserved */ | |
885 | 200 |
0 | 201 /* stream list */ |
202 for(i=0;i<n;i++) { | |
203 list2 = start_tag(pb, "LIST"); | |
204 put_tag(pb, "strl"); | |
885 | 205 |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
796
diff
changeset
|
206 stream = s->streams[i]->codec; |
0 | 207 |
208 /* stream generic header */ | |
209 strh = start_tag(pb, "strh"); | |
210 switch(stream->codec_type) { | |
781 | 211 case CODEC_TYPE_VIDEO: put_tag(pb, "vids"); break; |
212 case CODEC_TYPE_AUDIO: put_tag(pb, "auds"); break; | |
213 // case CODEC_TYPE_TEXT : put_tag(pb, "txts"); break; | |
214 case CODEC_TYPE_DATA : put_tag(pb, "dats"); break; | |
215 } | |
216 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
89
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
217 put_le32(pb, stream->codec_tag); |
781 | 218 else |
219 put_le32(pb, 1); | |
220 put_le32(pb, 0); /* flags */ | |
221 put_le16(pb, 0); /* priority */ | |
222 put_le16(pb, 0); /* language */ | |
223 put_le32(pb, 0); /* initial frame */ | |
224 | |
225 ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); | |
75
78bec272ce3a
read BITMAPINFOHEADER extra stuff (huffyuv decoding fixed)
michaelni
parents:
65
diff
changeset
|
226 |
781 | 227 put_le32(pb, au_scale); /* scale */ |
228 put_le32(pb, au_byterate); /* rate */ | |
229 av_set_pts_info(s->streams[i], 64, au_scale, au_byterate); | |
230 | |
231 put_le32(pb, 0); /* start */ | |
232 avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ | |
887 | 233 if (url_is_streamed(pb)) |
234 put_le32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ | |
235 else | |
236 put_le32(pb, 0); /* length, XXX: filled later */ | |
885 | 237 |
781 | 238 /* suggested buffer size */ //FIXME set at the end to largest chunk |
239 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
885 | 240 put_le32(pb, 1024 * 1024); |
781 | 241 else if(stream->codec_type == CODEC_TYPE_AUDIO) |
885 | 242 put_le32(pb, 12 * 1024); |
781 | 243 else |
885 | 244 put_le32(pb, 0); |
781 | 245 put_le32(pb, -1); /* quality */ |
246 put_le32(pb, au_ssize); /* sample size */ | |
247 put_le32(pb, 0); | |
248 put_le16(pb, stream->width); | |
249 put_le16(pb, stream->height); | |
0 | 250 end_tag(pb, strh); |
251 | |
781 | 252 if(stream->codec_type != CODEC_TYPE_DATA){ |
0 | 253 strf = start_tag(pb, "strf"); |
254 switch(stream->codec_type) { | |
255 case CODEC_TYPE_VIDEO: | |
887 | 256 put_bmp_header(pb, stream, codec_bmp_tags, 0); |
0 | 257 break; |
258 case CODEC_TYPE_AUDIO: | |
259 if (put_wav_header(pb, stream) < 0) { | |
260 return -1; | |
261 } | |
262 break; | |
263 default: | |
537 | 264 return -1; |
0 | 265 } |
266 end_tag(pb, strf); | |
781 | 267 } |
885 | 268 |
887 | 269 if (!url_is_streamed(pb)) { |
270 unsigned char tag[5]; | |
271 int j; | |
885 | 272 |
273 /* Starting to lay out AVI OpenDML master index. | |
887 | 274 * We want to make it JUNK entry for now, since we'd |
275 * like to get away without making AVI an OpenDML one | |
276 * for compatibility reasons. | |
277 */ | |
278 avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0; | |
279 avi->indexes[i].indx_start = start_tag(pb, "JUNK"); | |
280 put_le16(pb, 4); /* wLongsPerEntry */ | |
281 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ | |
282 put_byte(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ | |
283 put_le32(pb, 0); /* nEntriesInUse (will fill out later on) */ | |
284 put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type)); | |
285 /* dwChunkId */ | |
286 put_le64(pb, 0); /* dwReserved[3] | |
287 put_le32(pb, 0); Must be 0. */ | |
288 for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) | |
289 put_le64(pb, 0); | |
290 end_tag(pb, avi->indexes[i].indx_start); | |
291 } | |
885 | 292 |
3100 | 293 if( stream->codec_type == CODEC_TYPE_VIDEO |
3759
27537074f2a9
convert every muxer/demuxer to write/read sample_aspect_ratio from/to
aurel
parents:
3424
diff
changeset
|
294 && s->streams[i]->sample_aspect_ratio.num>0 |
27537074f2a9
convert every muxer/demuxer to write/read sample_aspect_ratio from/to
aurel
parents:
3424
diff
changeset
|
295 && s->streams[i]->sample_aspect_ratio.den>0){ |
3100 | 296 int vprp= start_tag(pb, "vprp"); |
3759
27537074f2a9
convert every muxer/demuxer to write/read sample_aspect_ratio from/to
aurel
parents:
3424
diff
changeset
|
297 AVRational dar = av_mul_q(s->streams[i]->sample_aspect_ratio, |
3100 | 298 (AVRational){stream->width, stream->height}); |
299 int num, den; | |
300 av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); | |
301 | |
302 put_le32(pb, 0); //video format = unknown | |
303 put_le32(pb, 0); //video standard= unknown | |
304 put_le32(pb, lrintf(1.0/av_q2d(stream->time_base))); | |
305 put_le32(pb, stream->width ); | |
306 put_le32(pb, stream->height); | |
3177 | 307 put_le16(pb, den); |
3100 | 308 put_le16(pb, num); |
309 put_le32(pb, stream->width ); | |
310 put_le32(pb, stream->height); | |
311 put_le32(pb, 1); //progressive FIXME | |
312 | |
313 put_le32(pb, stream->height); | |
314 put_le32(pb, stream->width ); | |
315 put_le32(pb, stream->height); | |
316 put_le32(pb, stream->width ); | |
317 put_le32(pb, 0); | |
318 put_le32(pb, 0); | |
319 | |
320 put_le32(pb, 0); | |
321 put_le32(pb, 0); | |
322 end_tag(pb, vprp); | |
323 } | |
324 | |
0 | 325 end_tag(pb, list2); |
326 } | |
885 | 327 |
119 | 328 if (!url_is_streamed(pb)) { |
329 /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ | |
330 avi->odml_list = start_tag(pb, "JUNK"); | |
331 put_tag(pb, "odml"); | |
332 put_tag(pb, "dmlh"); | |
333 put_le32(pb, 248); | |
334 for (i = 0; i < 248; i+= 4) | |
335 put_le32(pb, 0); | |
336 end_tag(pb, avi->odml_list); | |
337 } | |
0 | 338 |
339 end_tag(pb, list1); | |
885 | 340 |
1256 | 341 list2 = start_tag(pb, "LIST"); |
342 put_tag(pb, "INFO"); | |
4149 | 343 avi_write_info_tag2(s, "INAM", "Title", NULL); |
344 avi_write_info_tag2(s, "IART", "Artist", "Author"); | |
345 avi_write_info_tag2(s, "ICOP", "Copyright", NULL); | |
346 avi_write_info_tag2(s, "ICMT", "Comment", NULL); | |
347 avi_write_info_tag2(s, "IPRD", "Album", NULL); | |
348 avi_write_info_tag2(s, "IGNR", "Genre", NULL); | |
349 avi_write_info_tag2(s, "IPRT", "Track", NULL); | |
1256 | 350 if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) |
351 avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); | |
352 end_tag(pb, list2); | |
353 | |
354 /* some padding for easier tag editing */ | |
355 list2 = start_tag(pb, "JUNK"); | |
356 for (i = 0; i < 1016; i += 4) | |
357 put_le32(pb, 0); | |
358 end_tag(pb, list2); | |
359 | |
0 | 360 avi->movi_list = start_tag(pb, "LIST"); |
361 put_tag(pb, "movi"); | |
362 | |
363 put_flush_packet(pb); | |
364 | |
365 return 0; | |
366 } | |
367 | |
119 | 368 static int avi_write_ix(AVFormatContext *s) |
369 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
370 ByteIOContext *pb = s->pb; |
119 | 371 AVIContext *avi = s->priv_data; |
1332 | 372 char tag[5]; |
373 char ix_tag[] = "ix00"; | |
119 | 374 int i, j; |
885 | 375 |
976 | 376 assert(!url_is_streamed(pb)); |
873
7af647503b67
Support for streaming: dont write indexes and dont signal HAS_INDEX in header. Also set filesize to max in this case.
alex
parents:
863
diff
changeset
|
377 |
119 | 378 if (avi->riff_id > AVI_MASTER_INDEX_SIZE) |
379 return -1; | |
885 | 380 |
119 | 381 for (i=0;i<s->nb_streams;i++) { |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
382 int64_t ix, pos; |
885 | 383 |
887 | 384 avi_stream2fourcc(&tag[0], i, s->streams[i]->codec->codec_type); |
385 ix_tag[3] = '0' + i; | |
885 | 386 |
887 | 387 /* Writing AVI OpenDML leaf index chunk */ |
388 ix = url_ftell(pb); | |
389 put_tag(pb, &ix_tag[0]); /* ix?? */ | |
390 put_le32(pb, avi->indexes[i].entry * 8 + 24); | |
391 /* chunk size */ | |
119 | 392 put_le16(pb, 2); /* wLongsPerEntry */ |
887 | 393 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ |
394 put_byte(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ | |
395 put_le32(pb, avi->indexes[i].entry); | |
396 /* nEntriesInUse */ | |
397 put_tag(pb, &tag[0]); /* dwChunkId */ | |
398 put_le64(pb, avi->movi_list);/* qwBaseOffset */ | |
399 put_le32(pb, 0); /* dwReserved_3 (must be 0) */ | |
119 | 400 |
401 for (j=0; j<avi->indexes[i].entry; j++) { | |
402 AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j); | |
887 | 403 put_le32(pb, ie->pos + 8); |
404 put_le32(pb, ((uint32_t)ie->len & ~0x80000000) | | |
405 (ie->flags & 0x10 ? 0 : 0x80000000)); | |
119 | 406 } |
887 | 407 put_flush_packet(pb); |
119 | 408 pos = url_ftell(pb); |
885 | 409 |
887 | 410 /* Updating one entry in the AVI OpenDML master index */ |
411 url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET); | |
412 put_tag(pb, "indx"); /* enabling this entry */ | |
413 url_fskip(pb, 8); | |
414 put_le32(pb, avi->riff_id); /* nEntriesInUse */ | |
415 url_fskip(pb, 16*avi->riff_id); | |
416 put_le64(pb, ix); /* qwOffset */ | |
417 put_le32(pb, pos - ix); /* dwSize */ | |
418 put_le32(pb, avi->indexes[i].entry); /* dwDuration */ | |
119 | 419 |
887 | 420 url_fseek(pb, pos, SEEK_SET); |
119 | 421 } |
422 return 0; | |
423 } | |
424 | |
425 static int avi_write_idx1(AVFormatContext *s) | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
426 { |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
427 ByteIOContext *pb = s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
428 AVIContext *avi = s->priv_data; |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
429 int64_t idx_chunk; |
1267 | 430 int i; |
1332 | 431 char tag[5]; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
432 |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
433 if (!url_is_streamed(pb)) { |
887 | 434 AVIIentry* ie = 0, *tie; |
435 int entry[MAX_STREAMS]; | |
436 int empty, stream_id = -1; | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
437 |
887 | 438 idx_chunk = start_tag(pb, "idx1"); |
439 memset(&entry[0], 0, sizeof(entry)); | |
440 do { | |
441 empty = 1; | |
442 for (i=0; i<s->nb_streams; i++) { | |
443 if (avi->indexes[i].entry <= entry[i]) | |
444 continue; | |
885 | 445 |
887 | 446 tie = avi_get_ientry(&avi->indexes[i], entry[i]); |
447 if (empty || tie->pos < ie->pos) { | |
448 ie = tie; | |
449 stream_id = i; | |
450 } | |
451 empty = 0; | |
452 } | |
453 if (!empty) { | |
454 avi_stream2fourcc(&tag[0], stream_id, | |
455 s->streams[stream_id]->codec->codec_type); | |
456 put_tag(pb, &tag[0]); | |
457 put_le32(pb, ie->flags); | |
119 | 458 put_le32(pb, ie->pos); |
459 put_le32(pb, ie->len); | |
887 | 460 entry[stream_id]++; |
461 } | |
462 } while (!empty); | |
463 end_tag(pb, idx_chunk); | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
464 |
1267 | 465 avi_write_counters(s, avi->riff_id); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
466 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
467 return 0; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
468 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
469 |
468 | 470 static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 471 { |
472 AVIContext *avi = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
473 ByteIOContext *pb = s->pb; |
0 | 474 unsigned char tag[5]; |
468 | 475 unsigned int flags=0; |
476 const int stream_index= pkt->stream_index; | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
796
diff
changeset
|
477 AVCodecContext *enc= s->streams[stream_index]->codec; |
468 | 478 int size= pkt->size; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
479 |
1443
404048ea11bc
Replace most of the %lld and %llx by their (cleaner) PRI*64 counterparts.
diego
parents:
1415
diff
changeset
|
480 // av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index); |
724 | 481 while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){ |
479 | 482 AVPacket empty_packet; |
483 | |
484 av_init_packet(&empty_packet); | |
485 empty_packet.size= 0; | |
486 empty_packet.data= NULL; | |
487 empty_packet.stream_index= stream_index; | |
488 avi_write_packet(s, &empty_packet); | |
1443
404048ea11bc
Replace most of the %lld and %llx by their (cleaner) PRI*64 counterparts.
diego
parents:
1415
diff
changeset
|
489 // av_log(s, AV_LOG_DEBUG, "dup %"PRId64" %d\n", pkt->dts, avi->packet_count[stream_index]); |
479 | 490 } |
491 avi->packet_count[stream_index]++; | |
492 | |
873
7af647503b67
Support for streaming: dont write indexes and dont signal HAS_INDEX in header. Also set filesize to max in this case.
alex
parents:
863
diff
changeset
|
493 // Make sure to put an OpenDML chunk when the file size exceeds the limits |
885 | 494 if (!url_is_streamed(pb) && |
887 | 495 (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { |
885 | 496 |
119 | 497 avi_write_ix(s); |
498 end_tag(pb, avi->movi_list); | |
885 | 499 |
887 | 500 if (avi->riff_id == 1) |
501 avi_write_idx1(s); | |
119 | 502 |
887 | 503 end_tag(pb, avi->riff_start); |
504 avi->movi_list = avi_start_new_riff(avi, pb, "AVIX", "movi"); | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
505 } |
885 | 506 |
119 | 507 avi_stream2fourcc(&tag[0], stream_index, enc->codec_type); |
468 | 508 if(pkt->flags&PKT_FLAG_KEY) |
509 flags = 0x10; | |
119 | 510 if (enc->codec_type == CODEC_TYPE_AUDIO) { |
0 | 511 avi->audio_strm_length[stream_index] += size; |
468 | 512 } |
0 | 513 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
514 if (!url_is_streamed(s->pb)) { |
119 | 515 AVIIndex* idx = &avi->indexes[stream_index]; |
887 | 516 int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; |
517 int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; | |
119 | 518 if (idx->ents_allocated <= idx->entry) { |
887 | 519 idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); |
520 if (!idx->cluster) | |
521 return -1; | |
119 | 522 idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); |
887 | 523 if (!idx->cluster[cl]) |
524 return -1; | |
525 idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; | |
526 } | |
885 | 527 |
887 | 528 idx->cluster[cl][id].flags = flags; |
119 | 529 idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list; |
530 idx->cluster[cl][id].len = size; | |
887 | 531 idx->entry++; |
0 | 532 } |
885 | 533 |
0 | 534 put_buffer(pb, tag, 4); |
535 put_le32(pb, size); | |
468 | 536 put_buffer(pb, pkt->data, size); |
0 | 537 if (size & 1) |
538 put_byte(pb, 0); | |
539 | |
540 put_flush_packet(pb); | |
541 return 0; | |
542 } | |
543 | |
544 static int avi_write_trailer(AVFormatContext *s) | |
545 { | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
546 AVIContext *avi = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
547 ByteIOContext *pb = s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
548 int res = 0; |
119 | 549 int i, j, n, nb_frames; |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3872
diff
changeset
|
550 int64_t file_size; |
0 | 551 |
1676 | 552 if (!url_is_streamed(pb)){ |
553 if (avi->riff_id == 1) { | |
554 end_tag(pb, avi->movi_list); | |
555 res = avi_write_idx1(s); | |
556 end_tag(pb, avi->riff_start); | |
557 } else { | |
558 avi_write_ix(s); | |
559 end_tag(pb, avi->movi_list); | |
560 end_tag(pb, avi->riff_start); | |
119 | 561 |
1676 | 562 file_size = url_ftell(pb); |
563 url_fseek(pb, avi->odml_list - 8, SEEK_SET); | |
564 put_tag(pb, "LIST"); /* Making this AVI OpenDML one */ | |
565 url_fskip(pb, 16); | |
0 | 566 |
1676 | 567 for (n=nb_frames=0;n<s->nb_streams;n++) { |
568 AVCodecContext *stream = s->streams[n]->codec; | |
569 if (stream->codec_type == CODEC_TYPE_VIDEO) { | |
570 if (nb_frames < avi->packet_count[n]) | |
571 nb_frames = avi->packet_count[n]; | |
572 } else { | |
573 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) { | |
574 nb_frames += avi->packet_count[n]; | |
575 } | |
0 | 576 } |
577 } | |
1676 | 578 put_le32(pb, nb_frames); |
579 url_fseek(pb, file_size, SEEK_SET); | |
580 | |
581 avi_write_counters(s, avi->riff_id); | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
582 } |
873
7af647503b67
Support for streaming: dont write indexes and dont signal HAS_INDEX in header. Also set filesize to max in this case.
alex
parents:
863
diff
changeset
|
583 } |
119 | 584 put_flush_packet(pb); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
585 |
119 | 586 for (i=0; i<MAX_STREAMS; i++) { |
887 | 587 for (j=0; j<avi->indexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) |
119 | 588 av_free(avi->indexes[i].cluster[j]); |
887 | 589 av_free(avi->indexes[i].cluster); |
590 avi->indexes[i].cluster = NULL; | |
591 avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0; | |
119 | 592 } |
885 | 593 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
594 return res; |
0 | 595 } |
596 | |
1169 | 597 AVOutputFormat avi_muxer = { |
0 | 598 "avi", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3177
diff
changeset
|
599 NULL_IF_CONFIG_SMALL("AVI format"), |
0 | 600 "video/x-msvideo", |
601 "avi", | |
602 sizeof(AVIContext), | |
603 CODEC_ID_MP2, | |
106
4da5d55b3690
we really shouldnt use M$* as default codec -> use MPEG4 as default
michaelni
parents:
105
diff
changeset
|
604 CODEC_ID_MPEG4, |
0 | 605 avi_write_header, |
606 avi_write_packet, | |
607 avi_write_trailer, | |
3766
f062deeedb8d
Change codec_tag type from const struct AVCodecTag ** to const struct AVCodecTag * const *
reimar
parents:
3759
diff
changeset
|
608 .codec_tag= (const AVCodecTag* const []){codec_bmp_tags, codec_wav_tags, 0}, |
4567
963e3b76c7a6
Add AVFMT_VARIABLE_FPS to specify which muxers do not need duplicated frames.
michael
parents:
4477
diff
changeset
|
609 .flags= AVFMT_VARIABLE_FPS, |
0 | 610 }; |