Mercurial > libavformat.hg
annotate avienc.c @ 1206:e60bf67d9bf8 libavformat
The reader ignores the size of the ASF data object and keeps on
reading even beyond it.
Therefore if the ASF file includes an index object at its end, the
reader will treat the index like data, but of course will fail since
it thinks that the data is corrupted.
When reading an asf file with an index object, ffmpeg will
complain at the end of the file that it read an invalid header.
Patch by Kohn Emil Dan, < emild A cs P technion P ac P il >
Original thead:
Date: Apr 18, 2006 4:11 PM
Subject: [Ffmpeg-devel] Two ASF related bugs and fixes
author | gpoirier |
---|---|
date | Sat, 29 Jul 2006 16:07:19 +0000 |
parents | 6a5e58d2114b |
children | 2cddf00f92a6 |
rev | line source |
---|---|
0 | 1 /* |
2 * AVI encoder. | |
3 * Copyright (c) 2000 Fabrice Bellard. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
894
diff
changeset
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 */ |
19 #include "avformat.h" | |
20 #include "avi.h" | |
1172
6a5e58d2114b
move common stuff from avienc.c and wav.c to new file riff.c
mru
parents:
1169
diff
changeset
|
21 #include "riff.h" |
0 | 22 |
23 /* | |
885 | 24 * TODO: |
0 | 25 * - fill all fields if non streamed (nb_frames for example) |
26 */ | |
27 | |
1169 | 28 #ifdef CONFIG_AVI_MUXER |
119 | 29 typedef struct AVIIentry { |
30 unsigned int flags, pos, len; | |
31 } AVIIentry; | |
32 | |
33 #define AVI_INDEX_CLUSTER_SIZE 16384 | |
34 | |
0 | 35 typedef struct AVIIndex { |
119 | 36 offset_t indx_start; |
37 int entry; | |
38 int ents_allocated; | |
39 AVIIentry** cluster; | |
0 | 40 } AVIIndex; |
41 | |
42 typedef struct { | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
43 offset_t riff_start, movi_list, odml_list; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
44 offset_t frames_hdr_all, frames_hdr_strm[MAX_STREAMS]; |
0 | 45 int audio_strm_length[MAX_STREAMS]; |
119 | 46 int riff_id; |
479 | 47 int packet_count[MAX_STREAMS]; |
119 | 48 |
49 AVIIndex indexes[MAX_STREAMS]; | |
0 | 50 } AVIContext; |
51 | |
885 | 52 static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id) |
119 | 53 { |
54 int cl = ent_id / AVI_INDEX_CLUSTER_SIZE; | |
55 int id = ent_id % AVI_INDEX_CLUSTER_SIZE; | |
56 return &idx->cluster[cl][id]; | |
57 } | |
58 | |
885 | 59 static offset_t avi_start_new_riff(AVIContext *avi, ByteIOContext *pb, |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
60 const char* riff_tag, const char* list_tag) |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
61 { |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
62 offset_t loff; |
119 | 63 int i; |
885 | 64 |
119 | 65 avi->riff_id++; |
66 for (i=0; i<MAX_STREAMS; i++) | |
67 avi->indexes[i].entry = 0; | |
885 | 68 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
69 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
|
70 put_tag(pb, riff_tag); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
71 loff = start_tag(pb, "LIST"); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
72 put_tag(pb, list_tag); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
73 return loff; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
74 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
75 |
885 | 76 static unsigned char* avi_stream2fourcc(unsigned char* tag, int index, |
119 | 77 enum CodecType type) |
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 | |
0 | 92 static int avi_write_header(AVFormatContext *s) |
93 { | |
94 AVIContext *avi = s->priv_data; | |
95 ByteIOContext *pb = &s->pb; | |
96 int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; | |
97 AVCodecContext *stream, *video_enc; | |
98 offset_t list1, list2, strh, strf; | |
99 | |
100 /* header list */ | |
119 | 101 avi->riff_id = 0; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
102 list1 = avi_start_new_riff(avi, pb, "AVI ", "hdrl"); |
0 | 103 |
104 /* avi header */ | |
105 put_tag(pb, "avih"); | |
106 put_le32(pb, 14 * 4); | |
107 bitrate = 0; | |
108 | |
109 video_enc = NULL; | |
110 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
|
111 stream = s->streams[n]->codec; |
0 | 112 bitrate += stream->bit_rate; |
113 if (stream->codec_type == CODEC_TYPE_VIDEO) | |
114 video_enc = stream; | |
115 } | |
885 | 116 |
0 | 117 nb_frames = 0; |
118 | |
36
1188ad85857a
audio only avi patch by (Andriy Rysin <arysin at bcsii dot net>)
michaelni
parents:
15
diff
changeset
|
119 if(video_enc){ |
743 | 120 put_le32(pb, (uint32_t)(int64_t_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
|
121 } else { |
887 | 122 put_le32(pb, 0); |
36
1188ad85857a
audio only avi patch by (Andriy Rysin <arysin at bcsii dot net>)
michaelni
parents:
15
diff
changeset
|
123 } |
0 | 124 put_le32(pb, bitrate / 8); /* XXX: not quite exact */ |
125 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
|
126 if (url_is_streamed(pb)) |
887 | 127 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
|
128 else |
887 | 129 put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ |
0 | 130 avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */ |
131 put_le32(pb, nb_frames); /* nb frames, filled later */ | |
132 put_le32(pb, 0); /* initial frame */ | |
133 put_le32(pb, s->nb_streams); /* nb streams */ | |
134 put_le32(pb, 1024 * 1024); /* suggested buffer size */ | |
885 | 135 if(video_enc){ |
992 | 136 put_le32(pb, video_enc->width); |
137 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
|
138 } else { |
887 | 139 put_le32(pb, 0); |
140 put_le32(pb, 0); | |
885 | 141 } |
0 | 142 put_le32(pb, 0); /* reserved */ |
143 put_le32(pb, 0); /* reserved */ | |
144 put_le32(pb, 0); /* reserved */ | |
145 put_le32(pb, 0); /* reserved */ | |
885 | 146 |
0 | 147 /* stream list */ |
148 for(i=0;i<n;i++) { | |
149 list2 = start_tag(pb, "LIST"); | |
150 put_tag(pb, "strl"); | |
885 | 151 |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
796
diff
changeset
|
152 stream = s->streams[i]->codec; |
0 | 153 |
89
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
154 /* FourCC should really be set by the codec itself */ |
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
155 if (! stream->codec_tag) { |
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
156 stream->codec_tag = codec_get_bmp_tag(stream->codec_id); |
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
157 } |
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
158 |
0 | 159 /* stream generic header */ |
160 strh = start_tag(pb, "strh"); | |
161 switch(stream->codec_type) { | |
781 | 162 case CODEC_TYPE_VIDEO: put_tag(pb, "vids"); break; |
163 case CODEC_TYPE_AUDIO: put_tag(pb, "auds"); break; | |
164 // case CODEC_TYPE_TEXT : put_tag(pb, "txts"); break; | |
165 case CODEC_TYPE_DATA : put_tag(pb, "dats"); break; | |
166 } | |
167 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
89
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
168 put_le32(pb, stream->codec_tag); |
781 | 169 else |
170 put_le32(pb, 1); | |
171 put_le32(pb, 0); /* flags */ | |
172 put_le16(pb, 0); /* priority */ | |
173 put_le16(pb, 0); /* language */ | |
174 put_le32(pb, 0); /* initial frame */ | |
175 | |
176 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
|
177 |
781 | 178 put_le32(pb, au_scale); /* scale */ |
179 put_le32(pb, au_byterate); /* rate */ | |
180 av_set_pts_info(s->streams[i], 64, au_scale, au_byterate); | |
181 | |
182 put_le32(pb, 0); /* start */ | |
183 avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ | |
887 | 184 if (url_is_streamed(pb)) |
185 put_le32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ | |
186 else | |
187 put_le32(pb, 0); /* length, XXX: filled later */ | |
885 | 188 |
781 | 189 /* suggested buffer size */ //FIXME set at the end to largest chunk |
190 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
885 | 191 put_le32(pb, 1024 * 1024); |
781 | 192 else if(stream->codec_type == CODEC_TYPE_AUDIO) |
885 | 193 put_le32(pb, 12 * 1024); |
781 | 194 else |
885 | 195 put_le32(pb, 0); |
781 | 196 put_le32(pb, -1); /* quality */ |
197 put_le32(pb, au_ssize); /* sample size */ | |
198 put_le32(pb, 0); | |
199 put_le16(pb, stream->width); | |
200 put_le16(pb, stream->height); | |
0 | 201 end_tag(pb, strh); |
202 | |
781 | 203 if(stream->codec_type != CODEC_TYPE_DATA){ |
0 | 204 strf = start_tag(pb, "strf"); |
205 switch(stream->codec_type) { | |
206 case CODEC_TYPE_VIDEO: | |
887 | 207 put_bmp_header(pb, stream, codec_bmp_tags, 0); |
0 | 208 break; |
209 case CODEC_TYPE_AUDIO: | |
210 if (put_wav_header(pb, stream) < 0) { | |
211 av_free(avi); | |
212 return -1; | |
213 } | |
214 break; | |
215 default: | |
537 | 216 return -1; |
0 | 217 } |
218 end_tag(pb, strf); | |
781 | 219 } |
885 | 220 |
887 | 221 if (!url_is_streamed(pb)) { |
222 unsigned char tag[5]; | |
223 int j; | |
885 | 224 |
225 /* Starting to lay out AVI OpenDML master index. | |
887 | 226 * We want to make it JUNK entry for now, since we'd |
227 * like to get away without making AVI an OpenDML one | |
228 * for compatibility reasons. | |
229 */ | |
230 avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0; | |
231 avi->indexes[i].indx_start = start_tag(pb, "JUNK"); | |
232 put_le16(pb, 4); /* wLongsPerEntry */ | |
233 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ | |
234 put_byte(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ | |
235 put_le32(pb, 0); /* nEntriesInUse (will fill out later on) */ | |
236 put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type)); | |
237 /* dwChunkId */ | |
238 put_le64(pb, 0); /* dwReserved[3] | |
239 put_le32(pb, 0); Must be 0. */ | |
240 for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) | |
241 put_le64(pb, 0); | |
242 end_tag(pb, avi->indexes[i].indx_start); | |
243 } | |
885 | 244 |
0 | 245 end_tag(pb, list2); |
246 } | |
885 | 247 |
119 | 248 if (!url_is_streamed(pb)) { |
249 /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ | |
250 avi->odml_list = start_tag(pb, "JUNK"); | |
251 put_tag(pb, "odml"); | |
252 put_tag(pb, "dmlh"); | |
253 put_le32(pb, 248); | |
254 for (i = 0; i < 248; i+= 4) | |
255 put_le32(pb, 0); | |
256 end_tag(pb, avi->odml_list); | |
257 } | |
0 | 258 |
259 end_tag(pb, list1); | |
885 | 260 |
0 | 261 avi->movi_list = start_tag(pb, "LIST"); |
262 put_tag(pb, "movi"); | |
263 | |
264 put_flush_packet(pb); | |
265 | |
266 return 0; | |
267 } | |
268 | |
119 | 269 static int avi_write_ix(AVFormatContext *s) |
270 { | |
271 ByteIOContext *pb = &s->pb; | |
272 AVIContext *avi = s->priv_data; | |
273 unsigned char tag[5]; | |
274 unsigned char ix_tag[] = "ix00"; | |
275 int i, j; | |
885 | 276 |
976 | 277 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
|
278 |
119 | 279 if (avi->riff_id > AVI_MASTER_INDEX_SIZE) |
280 return -1; | |
885 | 281 |
119 | 282 for (i=0;i<s->nb_streams;i++) { |
887 | 283 offset_t ix, pos; |
885 | 284 |
887 | 285 avi_stream2fourcc(&tag[0], i, s->streams[i]->codec->codec_type); |
286 ix_tag[3] = '0' + i; | |
885 | 287 |
887 | 288 /* Writing AVI OpenDML leaf index chunk */ |
289 ix = url_ftell(pb); | |
290 put_tag(pb, &ix_tag[0]); /* ix?? */ | |
291 put_le32(pb, avi->indexes[i].entry * 8 + 24); | |
292 /* chunk size */ | |
119 | 293 put_le16(pb, 2); /* wLongsPerEntry */ |
887 | 294 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ |
295 put_byte(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ | |
296 put_le32(pb, avi->indexes[i].entry); | |
297 /* nEntriesInUse */ | |
298 put_tag(pb, &tag[0]); /* dwChunkId */ | |
299 put_le64(pb, avi->movi_list);/* qwBaseOffset */ | |
300 put_le32(pb, 0); /* dwReserved_3 (must be 0) */ | |
119 | 301 |
302 for (j=0; j<avi->indexes[i].entry; j++) { | |
303 AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j); | |
887 | 304 put_le32(pb, ie->pos + 8); |
305 put_le32(pb, ((uint32_t)ie->len & ~0x80000000) | | |
306 (ie->flags & 0x10 ? 0 : 0x80000000)); | |
119 | 307 } |
887 | 308 put_flush_packet(pb); |
119 | 309 pos = url_ftell(pb); |
885 | 310 |
887 | 311 /* Updating one entry in the AVI OpenDML master index */ |
312 url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET); | |
313 put_tag(pb, "indx"); /* enabling this entry */ | |
314 url_fskip(pb, 8); | |
315 put_le32(pb, avi->riff_id); /* nEntriesInUse */ | |
316 url_fskip(pb, 16*avi->riff_id); | |
317 put_le64(pb, ix); /* qwOffset */ | |
318 put_le32(pb, pos - ix); /* dwSize */ | |
319 put_le32(pb, avi->indexes[i].entry); /* dwDuration */ | |
119 | 320 |
887 | 321 url_fseek(pb, pos, SEEK_SET); |
119 | 322 } |
323 return 0; | |
324 } | |
325 | |
326 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
|
327 { |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
328 ByteIOContext *pb = &s->pb; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
329 AVIContext *avi = s->priv_data; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
330 offset_t file_size, idx_chunk; |
119 | 331 int i, n, nb_frames, au_byterate, au_ssize, au_scale; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
332 AVCodecContext *stream; |
119 | 333 unsigned char tag[5]; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
334 |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
335 if (!url_is_streamed(pb)) { |
887 | 336 AVIIentry* ie = 0, *tie; |
337 int entry[MAX_STREAMS]; | |
338 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
|
339 |
887 | 340 idx_chunk = start_tag(pb, "idx1"); |
341 memset(&entry[0], 0, sizeof(entry)); | |
342 do { | |
343 empty = 1; | |
344 for (i=0; i<s->nb_streams; i++) { | |
345 if (avi->indexes[i].entry <= entry[i]) | |
346 continue; | |
885 | 347 |
887 | 348 tie = avi_get_ientry(&avi->indexes[i], entry[i]); |
349 if (empty || tie->pos < ie->pos) { | |
350 ie = tie; | |
351 stream_id = i; | |
352 } | |
353 empty = 0; | |
354 } | |
355 if (!empty) { | |
356 avi_stream2fourcc(&tag[0], stream_id, | |
357 s->streams[stream_id]->codec->codec_type); | |
358 put_tag(pb, &tag[0]); | |
359 put_le32(pb, ie->flags); | |
119 | 360 put_le32(pb, ie->pos); |
361 put_le32(pb, ie->len); | |
887 | 362 entry[stream_id]++; |
363 } | |
364 } while (!empty); | |
365 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
|
366 |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
367 /* Fill in frame/sample counters */ |
887 | 368 file_size = url_ftell(pb); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
369 nb_frames = 0; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
370 for(n=0;n<s->nb_streams;n++) { |
993 | 371 assert(avi->frames_hdr_strm[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
|
372 stream = s->streams[n]->codec; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
373 url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET); |
781 | 374 ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); |
577 | 375 if (au_ssize == 0) { |
914
ef25e246c7f2
avoid using non constant fields of AVCodecContext in avi muxer
michael
parents:
896
diff
changeset
|
376 put_le32(pb, avi->packet_count[n]); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
377 } else { |
577 | 378 put_le32(pb, avi->audio_strm_length[n] / au_ssize); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
379 } |
993 | 380 if(stream->codec_type == CODEC_TYPE_VIDEO) |
381 nb_frames = FFMAX(nb_frames, avi->packet_count[n]); | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
382 } |
993 | 383 assert(avi->frames_hdr_all); |
384 url_fseek(pb, avi->frames_hdr_all, SEEK_SET); | |
385 put_le32(pb, nb_frames); | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
386 url_fseek(pb, file_size, SEEK_SET); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
387 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
388 return 0; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
389 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
390 |
468 | 391 static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 392 { |
393 AVIContext *avi = s->priv_data; | |
394 ByteIOContext *pb = &s->pb; | |
395 unsigned char tag[5]; | |
468 | 396 unsigned int flags=0; |
397 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
|
398 AVCodecContext *enc= s->streams[stream_index]->codec; |
468 | 399 int size= pkt->size; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
400 |
479 | 401 // av_log(s, AV_LOG_DEBUG, "%lld %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index); |
724 | 402 while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){ |
479 | 403 AVPacket empty_packet; |
404 | |
405 av_init_packet(&empty_packet); | |
406 empty_packet.size= 0; | |
407 empty_packet.data= NULL; | |
408 empty_packet.stream_index= stream_index; | |
409 avi_write_packet(s, &empty_packet); | |
410 // av_log(s, AV_LOG_DEBUG, "dup %lld %d\n", pkt->dts, avi->packet_count[stream_index]); | |
411 } | |
412 avi->packet_count[stream_index]++; | |
413 | |
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
|
414 // Make sure to put an OpenDML chunk when the file size exceeds the limits |
885 | 415 if (!url_is_streamed(pb) && |
887 | 416 (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { |
885 | 417 |
119 | 418 avi_write_ix(s); |
419 end_tag(pb, avi->movi_list); | |
885 | 420 |
887 | 421 if (avi->riff_id == 1) |
422 avi_write_idx1(s); | |
119 | 423 |
887 | 424 end_tag(pb, avi->riff_start); |
425 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
|
426 } |
885 | 427 |
119 | 428 avi_stream2fourcc(&tag[0], stream_index, enc->codec_type); |
468 | 429 if(pkt->flags&PKT_FLAG_KEY) |
430 flags = 0x10; | |
119 | 431 if (enc->codec_type == CODEC_TYPE_AUDIO) { |
0 | 432 avi->audio_strm_length[stream_index] += size; |
468 | 433 } |
0 | 434 |
435 if (!url_is_streamed(&s->pb)) { | |
119 | 436 AVIIndex* idx = &avi->indexes[stream_index]; |
887 | 437 int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; |
438 int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; | |
119 | 439 if (idx->ents_allocated <= idx->entry) { |
887 | 440 idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); |
441 if (!idx->cluster) | |
442 return -1; | |
119 | 443 idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); |
887 | 444 if (!idx->cluster[cl]) |
445 return -1; | |
446 idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; | |
447 } | |
885 | 448 |
887 | 449 idx->cluster[cl][id].flags = flags; |
119 | 450 idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list; |
451 idx->cluster[cl][id].len = size; | |
887 | 452 idx->entry++; |
0 | 453 } |
885 | 454 |
0 | 455 put_buffer(pb, tag, 4); |
456 put_le32(pb, size); | |
468 | 457 put_buffer(pb, pkt->data, size); |
0 | 458 if (size & 1) |
459 put_byte(pb, 0); | |
460 | |
461 put_flush_packet(pb); | |
462 return 0; | |
463 } | |
464 | |
465 static int avi_write_trailer(AVFormatContext *s) | |
466 { | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
467 AVIContext *avi = s->priv_data; |
0 | 468 ByteIOContext *pb = &s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
469 int res = 0; |
119 | 470 int i, j, n, nb_frames; |
471 offset_t file_size; | |
0 | 472 |
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
|
473 if (!url_is_streamed(pb)) |
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
|
474 { |
119 | 475 if (avi->riff_id == 1) { |
476 end_tag(pb, avi->movi_list); | |
477 res = avi_write_idx1(s); | |
887 | 478 end_tag(pb, avi->riff_start); |
119 | 479 } else { |
480 avi_write_ix(s); | |
481 end_tag(pb, avi->movi_list); | |
887 | 482 end_tag(pb, avi->riff_start); |
119 | 483 |
0 | 484 file_size = url_ftell(pb); |
887 | 485 url_fseek(pb, avi->odml_list - 8, SEEK_SET); |
486 put_tag(pb, "LIST"); /* Making this AVI OpenDML one */ | |
487 url_fskip(pb, 16); | |
0 | 488 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
489 for (n=nb_frames=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
|
490 AVCodecContext *stream = s->streams[n]->codec; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
491 if (stream->codec_type == CODEC_TYPE_VIDEO) { |
914
ef25e246c7f2
avoid using non constant fields of AVCodecContext in avi muxer
michael
parents:
896
diff
changeset
|
492 if (nb_frames < avi->packet_count[n]) |
ef25e246c7f2
avoid using non constant fields of AVCodecContext in avi muxer
michael
parents:
896
diff
changeset
|
493 nb_frames = avi->packet_count[n]; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
494 } else { |
232 | 495 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) { |
914
ef25e246c7f2
avoid using non constant fields of AVCodecContext in avi muxer
michael
parents:
896
diff
changeset
|
496 nb_frames += avi->packet_count[n]; |
0 | 497 } |
498 } | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
499 } |
887 | 500 put_le32(pb, nb_frames); |
501 url_fseek(pb, file_size, SEEK_SET); | |
119 | 502 } |
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
|
503 } |
119 | 504 put_flush_packet(pb); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
505 |
119 | 506 for (i=0; i<MAX_STREAMS; i++) { |
887 | 507 for (j=0; j<avi->indexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) |
119 | 508 av_free(avi->indexes[i].cluster[j]); |
887 | 509 av_free(avi->indexes[i].cluster); |
510 avi->indexes[i].cluster = NULL; | |
511 avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0; | |
119 | 512 } |
885 | 513 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
514 return res; |
0 | 515 } |
516 | |
1169 | 517 AVOutputFormat avi_muxer = { |
0 | 518 "avi", |
519 "avi format", | |
520 "video/x-msvideo", | |
521 "avi", | |
522 sizeof(AVIContext), | |
523 CODEC_ID_MP2, | |
106
4da5d55b3690
we really shouldnt use M$* as default codec -> use MPEG4 as default
michaelni
parents:
105
diff
changeset
|
524 CODEC_ID_MPEG4, |
0 | 525 avi_write_header, |
526 avi_write_packet, | |
527 avi_write_trailer, | |
528 }; | |
1169 | 529 #endif //CONFIG_AVI_MUXER |