Mercurial > libavformat.hg
annotate avienc.c @ 3754:8d267b43eaba libavformat
Move malloc() down until after all initializations, so that the resource is
only allocated if initialization worked. This means that on failure, we
don't have to deallocate it.
author | rbultje |
---|---|
date | Sat, 23 Aug 2008 18:46:30 +0000 |
parents | 7a0230981402 |
children | 27537074f2a9 |
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 |
0 | 3 * Copyright (c) 2000 Fabrice Bellard. |
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 | |
1169 | 30 #ifdef CONFIG_AVI_MUXER |
119 | 31 typedef struct AVIIentry { |
32 unsigned int flags, pos, len; | |
33 } AVIIentry; | |
34 | |
35 #define AVI_INDEX_CLUSTER_SIZE 16384 | |
36 | |
0 | 37 typedef struct AVIIndex { |
119 | 38 offset_t indx_start; |
39 int entry; | |
40 int ents_allocated; | |
41 AVIIentry** cluster; | |
0 | 42 } AVIIndex; |
43 | |
44 typedef struct { | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
45 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
|
46 offset_t frames_hdr_all, frames_hdr_strm[MAX_STREAMS]; |
0 | 47 int audio_strm_length[MAX_STREAMS]; |
119 | 48 int riff_id; |
479 | 49 int packet_count[MAX_STREAMS]; |
119 | 50 |
51 AVIIndex indexes[MAX_STREAMS]; | |
0 | 52 } AVIContext; |
53 | |
885 | 54 static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id) |
119 | 55 { |
56 int cl = ent_id / AVI_INDEX_CLUSTER_SIZE; | |
57 int id = ent_id % AVI_INDEX_CLUSTER_SIZE; | |
58 return &idx->cluster[cl][id]; | |
59 } | |
60 | |
885 | 61 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
|
62 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
|
63 { |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
64 offset_t loff; |
119 | 65 int i; |
885 | 66 |
119 | 67 avi->riff_id++; |
68 for (i=0; i<MAX_STREAMS; i++) | |
69 avi->indexes[i].entry = 0; | |
885 | 70 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
71 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
|
72 put_tag(pb, riff_tag); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
73 loff = start_tag(pb, "LIST"); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
74 put_tag(pb, list_tag); |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
75 return loff; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
76 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
77 |
1332 | 78 static char* avi_stream2fourcc(char* tag, int index, enum CodecType type) |
119 | 79 { |
80 tag[0] = '0'; | |
81 tag[1] = '0' + index; | |
82 if (type == CODEC_TYPE_VIDEO) { | |
83 tag[2] = 'd'; | |
84 tag[3] = 'c'; | |
85 } else { | |
86 tag[2] = 'w'; | |
87 tag[3] = 'b'; | |
88 } | |
89 tag[4] = '\0'; | |
90 return tag; | |
91 } | |
92 | |
1256 | 93 static void avi_write_info_tag(ByteIOContext *pb, const char *tag, const char *str) |
94 { | |
95 int len = strlen(str); | |
96 if (len > 0) { | |
97 len++; | |
98 put_tag(pb, tag); | |
99 put_le32(pb, len); | |
100 put_strz(pb, str); | |
101 if (len & 1) | |
102 put_byte(pb, 0); | |
103 } | |
104 } | |
105 | |
1267 | 106 static int avi_write_counters(AVFormatContext* s, int riff_id) |
107 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
108 ByteIOContext *pb = s->pb; |
1267 | 109 AVIContext *avi = s->priv_data; |
110 int n, au_byterate, au_ssize, au_scale, nb_frames = 0; | |
111 offset_t file_size; | |
112 AVCodecContext* stream; | |
113 | |
114 file_size = url_ftell(pb); | |
115 for(n = 0; n < s->nb_streams; n++) { | |
116 assert(avi->frames_hdr_strm[n]); | |
117 stream = s->streams[n]->codec; | |
118 url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET); | |
119 ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); | |
120 if(au_ssize == 0) { | |
121 put_le32(pb, avi->packet_count[n]); | |
122 } else { | |
123 put_le32(pb, avi->audio_strm_length[n] / au_ssize); | |
124 } | |
125 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
126 nb_frames = FFMAX(nb_frames, avi->packet_count[n]); | |
127 } | |
128 if(riff_id == 1) { | |
129 assert(avi->frames_hdr_all); | |
130 url_fseek(pb, avi->frames_hdr_all, SEEK_SET); | |
131 put_le32(pb, nb_frames); | |
132 } | |
133 url_fseek(pb, file_size, SEEK_SET); | |
134 | |
135 return 0; | |
136 } | |
137 | |
0 | 138 static int avi_write_header(AVFormatContext *s) |
139 { | |
140 AVIContext *avi = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
141 ByteIOContext *pb = s->pb; |
0 | 142 int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; |
143 AVCodecContext *stream, *video_enc; | |
144 offset_t list1, list2, strh, strf; | |
145 | |
146 /* header list */ | |
119 | 147 avi->riff_id = 0; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
148 list1 = avi_start_new_riff(avi, pb, "AVI ", "hdrl"); |
0 | 149 |
150 /* avi header */ | |
151 put_tag(pb, "avih"); | |
152 put_le32(pb, 14 * 4); | |
153 bitrate = 0; | |
154 | |
155 video_enc = NULL; | |
156 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
|
157 stream = s->streams[n]->codec; |
0 | 158 bitrate += stream->bit_rate; |
159 if (stream->codec_type == CODEC_TYPE_VIDEO) | |
160 video_enc = stream; | |
161 } | |
885 | 162 |
0 | 163 nb_frames = 0; |
164 | |
36
1188ad85857a
audio only avi patch by (Andriy Rysin <arysin at bcsii dot net>)
michaelni
parents:
15
diff
changeset
|
165 if(video_enc){ |
1556 | 166 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
|
167 } else { |
887 | 168 put_le32(pb, 0); |
36
1188ad85857a
audio only avi patch by (Andriy Rysin <arysin at bcsii dot net>)
michaelni
parents:
15
diff
changeset
|
169 } |
0 | 170 put_le32(pb, bitrate / 8); /* XXX: not quite exact */ |
171 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
|
172 if (url_is_streamed(pb)) |
887 | 173 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
|
174 else |
887 | 175 put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ |
0 | 176 avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */ |
177 put_le32(pb, nb_frames); /* nb frames, filled later */ | |
178 put_le32(pb, 0); /* initial frame */ | |
179 put_le32(pb, s->nb_streams); /* nb streams */ | |
180 put_le32(pb, 1024 * 1024); /* suggested buffer size */ | |
885 | 181 if(video_enc){ |
992 | 182 put_le32(pb, video_enc->width); |
183 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
|
184 } else { |
887 | 185 put_le32(pb, 0); |
186 put_le32(pb, 0); | |
885 | 187 } |
0 | 188 put_le32(pb, 0); /* reserved */ |
189 put_le32(pb, 0); /* reserved */ | |
190 put_le32(pb, 0); /* reserved */ | |
191 put_le32(pb, 0); /* reserved */ | |
885 | 192 |
0 | 193 /* stream list */ |
194 for(i=0;i<n;i++) { | |
195 list2 = start_tag(pb, "LIST"); | |
196 put_tag(pb, "strl"); | |
885 | 197 |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
796
diff
changeset
|
198 stream = s->streams[i]->codec; |
0 | 199 |
200 /* stream generic header */ | |
201 strh = start_tag(pb, "strh"); | |
202 switch(stream->codec_type) { | |
781 | 203 case CODEC_TYPE_VIDEO: put_tag(pb, "vids"); break; |
204 case CODEC_TYPE_AUDIO: put_tag(pb, "auds"); break; | |
205 // case CODEC_TYPE_TEXT : put_tag(pb, "txts"); break; | |
206 case CODEC_TYPE_DATA : put_tag(pb, "dats"); break; | |
207 } | |
208 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
89
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
209 put_le32(pb, stream->codec_tag); |
781 | 210 else |
211 put_le32(pb, 1); | |
212 put_le32(pb, 0); /* flags */ | |
213 put_le16(pb, 0); /* priority */ | |
214 put_le16(pb, 0); /* language */ | |
215 put_le32(pb, 0); /* initial frame */ | |
216 | |
217 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
|
218 |
781 | 219 put_le32(pb, au_scale); /* scale */ |
220 put_le32(pb, au_byterate); /* rate */ | |
221 av_set_pts_info(s->streams[i], 64, au_scale, au_byterate); | |
222 | |
223 put_le32(pb, 0); /* start */ | |
224 avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ | |
887 | 225 if (url_is_streamed(pb)) |
226 put_le32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ | |
227 else | |
228 put_le32(pb, 0); /* length, XXX: filled later */ | |
885 | 229 |
781 | 230 /* suggested buffer size */ //FIXME set at the end to largest chunk |
231 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
885 | 232 put_le32(pb, 1024 * 1024); |
781 | 233 else if(stream->codec_type == CODEC_TYPE_AUDIO) |
885 | 234 put_le32(pb, 12 * 1024); |
781 | 235 else |
885 | 236 put_le32(pb, 0); |
781 | 237 put_le32(pb, -1); /* quality */ |
238 put_le32(pb, au_ssize); /* sample size */ | |
239 put_le32(pb, 0); | |
240 put_le16(pb, stream->width); | |
241 put_le16(pb, stream->height); | |
0 | 242 end_tag(pb, strh); |
243 | |
781 | 244 if(stream->codec_type != CODEC_TYPE_DATA){ |
0 | 245 strf = start_tag(pb, "strf"); |
246 switch(stream->codec_type) { | |
247 case CODEC_TYPE_VIDEO: | |
887 | 248 put_bmp_header(pb, stream, codec_bmp_tags, 0); |
0 | 249 break; |
250 case CODEC_TYPE_AUDIO: | |
251 if (put_wav_header(pb, stream) < 0) { | |
252 av_free(avi); | |
253 return -1; | |
254 } | |
255 break; | |
256 default: | |
537 | 257 return -1; |
0 | 258 } |
259 end_tag(pb, strf); | |
781 | 260 } |
885 | 261 |
887 | 262 if (!url_is_streamed(pb)) { |
263 unsigned char tag[5]; | |
264 int j; | |
885 | 265 |
266 /* Starting to lay out AVI OpenDML master index. | |
887 | 267 * We want to make it JUNK entry for now, since we'd |
268 * like to get away without making AVI an OpenDML one | |
269 * for compatibility reasons. | |
270 */ | |
271 avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0; | |
272 avi->indexes[i].indx_start = start_tag(pb, "JUNK"); | |
273 put_le16(pb, 4); /* wLongsPerEntry */ | |
274 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ | |
275 put_byte(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ | |
276 put_le32(pb, 0); /* nEntriesInUse (will fill out later on) */ | |
277 put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type)); | |
278 /* dwChunkId */ | |
279 put_le64(pb, 0); /* dwReserved[3] | |
280 put_le32(pb, 0); Must be 0. */ | |
281 for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) | |
282 put_le64(pb, 0); | |
283 end_tag(pb, avi->indexes[i].indx_start); | |
284 } | |
885 | 285 |
3100 | 286 if( stream->codec_type == CODEC_TYPE_VIDEO |
287 && stream->sample_aspect_ratio.num>0 | |
288 && stream->sample_aspect_ratio.den>0){ | |
289 int vprp= start_tag(pb, "vprp"); | |
290 AVRational dar = av_mul_q(stream->sample_aspect_ratio, | |
291 (AVRational){stream->width, stream->height}); | |
292 int num, den; | |
293 av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); | |
294 | |
295 put_le32(pb, 0); //video format = unknown | |
296 put_le32(pb, 0); //video standard= unknown | |
297 put_le32(pb, lrintf(1.0/av_q2d(stream->time_base))); | |
298 put_le32(pb, stream->width ); | |
299 put_le32(pb, stream->height); | |
3177 | 300 put_le16(pb, den); |
3100 | 301 put_le16(pb, num); |
302 put_le32(pb, stream->width ); | |
303 put_le32(pb, stream->height); | |
304 put_le32(pb, 1); //progressive FIXME | |
305 | |
306 put_le32(pb, stream->height); | |
307 put_le32(pb, stream->width ); | |
308 put_le32(pb, stream->height); | |
309 put_le32(pb, stream->width ); | |
310 put_le32(pb, 0); | |
311 put_le32(pb, 0); | |
312 | |
313 put_le32(pb, 0); | |
314 put_le32(pb, 0); | |
315 end_tag(pb, vprp); | |
316 } | |
317 | |
0 | 318 end_tag(pb, list2); |
319 } | |
885 | 320 |
119 | 321 if (!url_is_streamed(pb)) { |
322 /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ | |
323 avi->odml_list = start_tag(pb, "JUNK"); | |
324 put_tag(pb, "odml"); | |
325 put_tag(pb, "dmlh"); | |
326 put_le32(pb, 248); | |
327 for (i = 0; i < 248; i+= 4) | |
328 put_le32(pb, 0); | |
329 end_tag(pb, avi->odml_list); | |
330 } | |
0 | 331 |
332 end_tag(pb, list1); | |
885 | 333 |
1256 | 334 list2 = start_tag(pb, "LIST"); |
335 put_tag(pb, "INFO"); | |
336 avi_write_info_tag(pb, "INAM", s->title); | |
337 avi_write_info_tag(pb, "IART", s->author); | |
338 avi_write_info_tag(pb, "ICOP", s->copyright); | |
339 avi_write_info_tag(pb, "ICMT", s->comment); | |
340 avi_write_info_tag(pb, "IPRD", s->album); | |
341 avi_write_info_tag(pb, "IGNR", s->genre); | |
1297
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
342 if (s->track) { |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
343 char str_track[4]; |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
344 snprintf(str_track, 4, "%d", s->track); |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
345 avi_write_info_tag(pb, "IPRT", str_track); |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
346 } |
1256 | 347 if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) |
348 avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); | |
349 end_tag(pb, list2); | |
350 | |
351 /* some padding for easier tag editing */ | |
352 list2 = start_tag(pb, "JUNK"); | |
353 for (i = 0; i < 1016; i += 4) | |
354 put_le32(pb, 0); | |
355 end_tag(pb, list2); | |
356 | |
0 | 357 avi->movi_list = start_tag(pb, "LIST"); |
358 put_tag(pb, "movi"); | |
359 | |
360 put_flush_packet(pb); | |
361 | |
362 return 0; | |
363 } | |
364 | |
119 | 365 static int avi_write_ix(AVFormatContext *s) |
366 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
367 ByteIOContext *pb = s->pb; |
119 | 368 AVIContext *avi = s->priv_data; |
1332 | 369 char tag[5]; |
370 char ix_tag[] = "ix00"; | |
119 | 371 int i, j; |
885 | 372 |
976 | 373 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
|
374 |
119 | 375 if (avi->riff_id > AVI_MASTER_INDEX_SIZE) |
376 return -1; | |
885 | 377 |
119 | 378 for (i=0;i<s->nb_streams;i++) { |
887 | 379 offset_t ix, pos; |
885 | 380 |
887 | 381 avi_stream2fourcc(&tag[0], i, s->streams[i]->codec->codec_type); |
382 ix_tag[3] = '0' + i; | |
885 | 383 |
887 | 384 /* Writing AVI OpenDML leaf index chunk */ |
385 ix = url_ftell(pb); | |
386 put_tag(pb, &ix_tag[0]); /* ix?? */ | |
387 put_le32(pb, avi->indexes[i].entry * 8 + 24); | |
388 /* chunk size */ | |
119 | 389 put_le16(pb, 2); /* wLongsPerEntry */ |
887 | 390 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ |
391 put_byte(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ | |
392 put_le32(pb, avi->indexes[i].entry); | |
393 /* nEntriesInUse */ | |
394 put_tag(pb, &tag[0]); /* dwChunkId */ | |
395 put_le64(pb, avi->movi_list);/* qwBaseOffset */ | |
396 put_le32(pb, 0); /* dwReserved_3 (must be 0) */ | |
119 | 397 |
398 for (j=0; j<avi->indexes[i].entry; j++) { | |
399 AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j); | |
887 | 400 put_le32(pb, ie->pos + 8); |
401 put_le32(pb, ((uint32_t)ie->len & ~0x80000000) | | |
402 (ie->flags & 0x10 ? 0 : 0x80000000)); | |
119 | 403 } |
887 | 404 put_flush_packet(pb); |
119 | 405 pos = url_ftell(pb); |
885 | 406 |
887 | 407 /* Updating one entry in the AVI OpenDML master index */ |
408 url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET); | |
409 put_tag(pb, "indx"); /* enabling this entry */ | |
410 url_fskip(pb, 8); | |
411 put_le32(pb, avi->riff_id); /* nEntriesInUse */ | |
412 url_fskip(pb, 16*avi->riff_id); | |
413 put_le64(pb, ix); /* qwOffset */ | |
414 put_le32(pb, pos - ix); /* dwSize */ | |
415 put_le32(pb, avi->indexes[i].entry); /* dwDuration */ | |
119 | 416 |
887 | 417 url_fseek(pb, pos, SEEK_SET); |
119 | 418 } |
419 return 0; | |
420 } | |
421 | |
422 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
|
423 { |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
424 ByteIOContext *pb = s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
425 AVIContext *avi = s->priv_data; |
1267 | 426 offset_t idx_chunk; |
427 int i; | |
1332 | 428 char tag[5]; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
429 |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
430 if (!url_is_streamed(pb)) { |
887 | 431 AVIIentry* ie = 0, *tie; |
432 int entry[MAX_STREAMS]; | |
433 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
|
434 |
887 | 435 idx_chunk = start_tag(pb, "idx1"); |
436 memset(&entry[0], 0, sizeof(entry)); | |
437 do { | |
438 empty = 1; | |
439 for (i=0; i<s->nb_streams; i++) { | |
440 if (avi->indexes[i].entry <= entry[i]) | |
441 continue; | |
885 | 442 |
887 | 443 tie = avi_get_ientry(&avi->indexes[i], entry[i]); |
444 if (empty || tie->pos < ie->pos) { | |
445 ie = tie; | |
446 stream_id = i; | |
447 } | |
448 empty = 0; | |
449 } | |
450 if (!empty) { | |
451 avi_stream2fourcc(&tag[0], stream_id, | |
452 s->streams[stream_id]->codec->codec_type); | |
453 put_tag(pb, &tag[0]); | |
454 put_le32(pb, ie->flags); | |
119 | 455 put_le32(pb, ie->pos); |
456 put_le32(pb, ie->len); | |
887 | 457 entry[stream_id]++; |
458 } | |
459 } while (!empty); | |
460 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
|
461 |
1267 | 462 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
|
463 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
464 return 0; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
465 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
466 |
468 | 467 static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 468 { |
469 AVIContext *avi = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
470 ByteIOContext *pb = s->pb; |
0 | 471 unsigned char tag[5]; |
468 | 472 unsigned int flags=0; |
473 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
|
474 AVCodecContext *enc= s->streams[stream_index]->codec; |
468 | 475 int size= pkt->size; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
476 |
1443
404048ea11bc
Replace most of the %lld and %llx by their (cleaner) PRI*64 counterparts.
diego
parents:
1415
diff
changeset
|
477 // av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index); |
724 | 478 while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){ |
479 | 479 AVPacket empty_packet; |
480 | |
481 av_init_packet(&empty_packet); | |
482 empty_packet.size= 0; | |
483 empty_packet.data= NULL; | |
484 empty_packet.stream_index= stream_index; | |
485 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
|
486 // av_log(s, AV_LOG_DEBUG, "dup %"PRId64" %d\n", pkt->dts, avi->packet_count[stream_index]); |
479 | 487 } |
488 avi->packet_count[stream_index]++; | |
489 | |
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
|
490 // Make sure to put an OpenDML chunk when the file size exceeds the limits |
885 | 491 if (!url_is_streamed(pb) && |
887 | 492 (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { |
885 | 493 |
119 | 494 avi_write_ix(s); |
495 end_tag(pb, avi->movi_list); | |
885 | 496 |
887 | 497 if (avi->riff_id == 1) |
498 avi_write_idx1(s); | |
119 | 499 |
887 | 500 end_tag(pb, avi->riff_start); |
501 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
|
502 } |
885 | 503 |
119 | 504 avi_stream2fourcc(&tag[0], stream_index, enc->codec_type); |
468 | 505 if(pkt->flags&PKT_FLAG_KEY) |
506 flags = 0x10; | |
119 | 507 if (enc->codec_type == CODEC_TYPE_AUDIO) { |
0 | 508 avi->audio_strm_length[stream_index] += size; |
468 | 509 } |
0 | 510 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
511 if (!url_is_streamed(s->pb)) { |
119 | 512 AVIIndex* idx = &avi->indexes[stream_index]; |
887 | 513 int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; |
514 int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; | |
119 | 515 if (idx->ents_allocated <= idx->entry) { |
887 | 516 idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); |
517 if (!idx->cluster) | |
518 return -1; | |
119 | 519 idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); |
887 | 520 if (!idx->cluster[cl]) |
521 return -1; | |
522 idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; | |
523 } | |
885 | 524 |
887 | 525 idx->cluster[cl][id].flags = flags; |
119 | 526 idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list; |
527 idx->cluster[cl][id].len = size; | |
887 | 528 idx->entry++; |
0 | 529 } |
885 | 530 |
0 | 531 put_buffer(pb, tag, 4); |
532 put_le32(pb, size); | |
468 | 533 put_buffer(pb, pkt->data, size); |
0 | 534 if (size & 1) |
535 put_byte(pb, 0); | |
536 | |
537 put_flush_packet(pb); | |
538 return 0; | |
539 } | |
540 | |
541 static int avi_write_trailer(AVFormatContext *s) | |
542 { | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
543 AVIContext *avi = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
544 ByteIOContext *pb = s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
545 int res = 0; |
119 | 546 int i, j, n, nb_frames; |
547 offset_t file_size; | |
0 | 548 |
1676 | 549 if (!url_is_streamed(pb)){ |
550 if (avi->riff_id == 1) { | |
551 end_tag(pb, avi->movi_list); | |
552 res = avi_write_idx1(s); | |
553 end_tag(pb, avi->riff_start); | |
554 } else { | |
555 avi_write_ix(s); | |
556 end_tag(pb, avi->movi_list); | |
557 end_tag(pb, avi->riff_start); | |
119 | 558 |
1676 | 559 file_size = url_ftell(pb); |
560 url_fseek(pb, avi->odml_list - 8, SEEK_SET); | |
561 put_tag(pb, "LIST"); /* Making this AVI OpenDML one */ | |
562 url_fskip(pb, 16); | |
0 | 563 |
1676 | 564 for (n=nb_frames=0;n<s->nb_streams;n++) { |
565 AVCodecContext *stream = s->streams[n]->codec; | |
566 if (stream->codec_type == CODEC_TYPE_VIDEO) { | |
567 if (nb_frames < avi->packet_count[n]) | |
568 nb_frames = avi->packet_count[n]; | |
569 } else { | |
570 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) { | |
571 nb_frames += avi->packet_count[n]; | |
572 } | |
0 | 573 } |
574 } | |
1676 | 575 put_le32(pb, nb_frames); |
576 url_fseek(pb, file_size, SEEK_SET); | |
577 | |
578 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
|
579 } |
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
|
580 } |
119 | 581 put_flush_packet(pb); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
582 |
119 | 583 for (i=0; i<MAX_STREAMS; i++) { |
887 | 584 for (j=0; j<avi->indexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) |
119 | 585 av_free(avi->indexes[i].cluster[j]); |
887 | 586 av_free(avi->indexes[i].cluster); |
587 avi->indexes[i].cluster = NULL; | |
588 avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0; | |
119 | 589 } |
885 | 590 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
591 return res; |
0 | 592 } |
593 | |
1169 | 594 AVOutputFormat avi_muxer = { |
0 | 595 "avi", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3177
diff
changeset
|
596 NULL_IF_CONFIG_SMALL("AVI format"), |
0 | 597 "video/x-msvideo", |
598 "avi", | |
599 sizeof(AVIContext), | |
600 CODEC_ID_MP2, | |
106
4da5d55b3690
we really shouldnt use M$* as default codec -> use MPEG4 as default
michaelni
parents:
105
diff
changeset
|
601 CODEC_ID_MPEG4, |
0 | 602 avi_write_header, |
603 avi_write_packet, | |
604 avi_write_trailer, | |
1679 | 605 .codec_tag= (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, 0}, |
0 | 606 }; |
1169 | 607 #endif //CONFIG_AVI_MUXER |