Mercurial > libavformat.hg
annotate avienc.c @ 3068:9cc9ff5aff9c libavformat
set bps to uncompressed original sound data for compressed audio
according to aiff specs, qt set it to 16 for mace and ima4,
fail if block align is not set.
author | bcoudurier |
---|---|
date | Mon, 25 Feb 2008 12:00:31 +0000 |
parents | d52c718e83f9 |
children | 5f769b20cc76 |
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 |
0 | 286 end_tag(pb, list2); |
287 } | |
885 | 288 |
119 | 289 if (!url_is_streamed(pb)) { |
290 /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ | |
291 avi->odml_list = start_tag(pb, "JUNK"); | |
292 put_tag(pb, "odml"); | |
293 put_tag(pb, "dmlh"); | |
294 put_le32(pb, 248); | |
295 for (i = 0; i < 248; i+= 4) | |
296 put_le32(pb, 0); | |
297 end_tag(pb, avi->odml_list); | |
298 } | |
0 | 299 |
300 end_tag(pb, list1); | |
885 | 301 |
1256 | 302 list2 = start_tag(pb, "LIST"); |
303 put_tag(pb, "INFO"); | |
304 avi_write_info_tag(pb, "INAM", s->title); | |
305 avi_write_info_tag(pb, "IART", s->author); | |
306 avi_write_info_tag(pb, "ICOP", s->copyright); | |
307 avi_write_info_tag(pb, "ICMT", s->comment); | |
308 avi_write_info_tag(pb, "IPRD", s->album); | |
309 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
|
310 if (s->track) { |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
311 char str_track[4]; |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
312 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
|
313 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
|
314 } |
1256 | 315 if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) |
316 avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); | |
317 end_tag(pb, list2); | |
318 | |
319 /* some padding for easier tag editing */ | |
320 list2 = start_tag(pb, "JUNK"); | |
321 for (i = 0; i < 1016; i += 4) | |
322 put_le32(pb, 0); | |
323 end_tag(pb, list2); | |
324 | |
0 | 325 avi->movi_list = start_tag(pb, "LIST"); |
326 put_tag(pb, "movi"); | |
327 | |
328 put_flush_packet(pb); | |
329 | |
330 return 0; | |
331 } | |
332 | |
119 | 333 static int avi_write_ix(AVFormatContext *s) |
334 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
335 ByteIOContext *pb = s->pb; |
119 | 336 AVIContext *avi = s->priv_data; |
1332 | 337 char tag[5]; |
338 char ix_tag[] = "ix00"; | |
119 | 339 int i, j; |
885 | 340 |
976 | 341 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
|
342 |
119 | 343 if (avi->riff_id > AVI_MASTER_INDEX_SIZE) |
344 return -1; | |
885 | 345 |
119 | 346 for (i=0;i<s->nb_streams;i++) { |
887 | 347 offset_t ix, pos; |
885 | 348 |
887 | 349 avi_stream2fourcc(&tag[0], i, s->streams[i]->codec->codec_type); |
350 ix_tag[3] = '0' + i; | |
885 | 351 |
887 | 352 /* Writing AVI OpenDML leaf index chunk */ |
353 ix = url_ftell(pb); | |
354 put_tag(pb, &ix_tag[0]); /* ix?? */ | |
355 put_le32(pb, avi->indexes[i].entry * 8 + 24); | |
356 /* chunk size */ | |
119 | 357 put_le16(pb, 2); /* wLongsPerEntry */ |
887 | 358 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ |
359 put_byte(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ | |
360 put_le32(pb, avi->indexes[i].entry); | |
361 /* nEntriesInUse */ | |
362 put_tag(pb, &tag[0]); /* dwChunkId */ | |
363 put_le64(pb, avi->movi_list);/* qwBaseOffset */ | |
364 put_le32(pb, 0); /* dwReserved_3 (must be 0) */ | |
119 | 365 |
366 for (j=0; j<avi->indexes[i].entry; j++) { | |
367 AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j); | |
887 | 368 put_le32(pb, ie->pos + 8); |
369 put_le32(pb, ((uint32_t)ie->len & ~0x80000000) | | |
370 (ie->flags & 0x10 ? 0 : 0x80000000)); | |
119 | 371 } |
887 | 372 put_flush_packet(pb); |
119 | 373 pos = url_ftell(pb); |
885 | 374 |
887 | 375 /* Updating one entry in the AVI OpenDML master index */ |
376 url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET); | |
377 put_tag(pb, "indx"); /* enabling this entry */ | |
378 url_fskip(pb, 8); | |
379 put_le32(pb, avi->riff_id); /* nEntriesInUse */ | |
380 url_fskip(pb, 16*avi->riff_id); | |
381 put_le64(pb, ix); /* qwOffset */ | |
382 put_le32(pb, pos - ix); /* dwSize */ | |
383 put_le32(pb, avi->indexes[i].entry); /* dwDuration */ | |
119 | 384 |
887 | 385 url_fseek(pb, pos, SEEK_SET); |
119 | 386 } |
387 return 0; | |
388 } | |
389 | |
390 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
|
391 { |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
392 ByteIOContext *pb = s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
393 AVIContext *avi = s->priv_data; |
1267 | 394 offset_t idx_chunk; |
395 int i; | |
1332 | 396 char tag[5]; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
397 |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
398 if (!url_is_streamed(pb)) { |
887 | 399 AVIIentry* ie = 0, *tie; |
400 int entry[MAX_STREAMS]; | |
401 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
|
402 |
887 | 403 idx_chunk = start_tag(pb, "idx1"); |
404 memset(&entry[0], 0, sizeof(entry)); | |
405 do { | |
406 empty = 1; | |
407 for (i=0; i<s->nb_streams; i++) { | |
408 if (avi->indexes[i].entry <= entry[i]) | |
409 continue; | |
885 | 410 |
887 | 411 tie = avi_get_ientry(&avi->indexes[i], entry[i]); |
412 if (empty || tie->pos < ie->pos) { | |
413 ie = tie; | |
414 stream_id = i; | |
415 } | |
416 empty = 0; | |
417 } | |
418 if (!empty) { | |
419 avi_stream2fourcc(&tag[0], stream_id, | |
420 s->streams[stream_id]->codec->codec_type); | |
421 put_tag(pb, &tag[0]); | |
422 put_le32(pb, ie->flags); | |
119 | 423 put_le32(pb, ie->pos); |
424 put_le32(pb, ie->len); | |
887 | 425 entry[stream_id]++; |
426 } | |
427 } while (!empty); | |
428 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
|
429 |
1267 | 430 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
|
431 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
432 return 0; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
433 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
434 |
468 | 435 static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 436 { |
437 AVIContext *avi = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
438 ByteIOContext *pb = s->pb; |
0 | 439 unsigned char tag[5]; |
468 | 440 unsigned int flags=0; |
441 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
|
442 AVCodecContext *enc= s->streams[stream_index]->codec; |
468 | 443 int size= pkt->size; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
444 |
1443
404048ea11bc
Replace most of the %lld and %llx by their (cleaner) PRI*64 counterparts.
diego
parents:
1415
diff
changeset
|
445 // av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index); |
724 | 446 while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){ |
479 | 447 AVPacket empty_packet; |
448 | |
449 av_init_packet(&empty_packet); | |
450 empty_packet.size= 0; | |
451 empty_packet.data= NULL; | |
452 empty_packet.stream_index= stream_index; | |
453 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
|
454 // av_log(s, AV_LOG_DEBUG, "dup %"PRId64" %d\n", pkt->dts, avi->packet_count[stream_index]); |
479 | 455 } |
456 avi->packet_count[stream_index]++; | |
457 | |
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
|
458 // Make sure to put an OpenDML chunk when the file size exceeds the limits |
885 | 459 if (!url_is_streamed(pb) && |
887 | 460 (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { |
885 | 461 |
119 | 462 avi_write_ix(s); |
463 end_tag(pb, avi->movi_list); | |
885 | 464 |
887 | 465 if (avi->riff_id == 1) |
466 avi_write_idx1(s); | |
119 | 467 |
887 | 468 end_tag(pb, avi->riff_start); |
469 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
|
470 } |
885 | 471 |
119 | 472 avi_stream2fourcc(&tag[0], stream_index, enc->codec_type); |
468 | 473 if(pkt->flags&PKT_FLAG_KEY) |
474 flags = 0x10; | |
119 | 475 if (enc->codec_type == CODEC_TYPE_AUDIO) { |
0 | 476 avi->audio_strm_length[stream_index] += size; |
468 | 477 } |
0 | 478 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
479 if (!url_is_streamed(s->pb)) { |
119 | 480 AVIIndex* idx = &avi->indexes[stream_index]; |
887 | 481 int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; |
482 int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; | |
119 | 483 if (idx->ents_allocated <= idx->entry) { |
887 | 484 idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); |
485 if (!idx->cluster) | |
486 return -1; | |
119 | 487 idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); |
887 | 488 if (!idx->cluster[cl]) |
489 return -1; | |
490 idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; | |
491 } | |
885 | 492 |
887 | 493 idx->cluster[cl][id].flags = flags; |
119 | 494 idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list; |
495 idx->cluster[cl][id].len = size; | |
887 | 496 idx->entry++; |
0 | 497 } |
885 | 498 |
0 | 499 put_buffer(pb, tag, 4); |
500 put_le32(pb, size); | |
468 | 501 put_buffer(pb, pkt->data, size); |
0 | 502 if (size & 1) |
503 put_byte(pb, 0); | |
504 | |
505 put_flush_packet(pb); | |
506 return 0; | |
507 } | |
508 | |
509 static int avi_write_trailer(AVFormatContext *s) | |
510 { | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
511 AVIContext *avi = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
512 ByteIOContext *pb = s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
513 int res = 0; |
119 | 514 int i, j, n, nb_frames; |
515 offset_t file_size; | |
0 | 516 |
1676 | 517 if (!url_is_streamed(pb)){ |
518 if (avi->riff_id == 1) { | |
519 end_tag(pb, avi->movi_list); | |
520 res = avi_write_idx1(s); | |
521 end_tag(pb, avi->riff_start); | |
522 } else { | |
523 avi_write_ix(s); | |
524 end_tag(pb, avi->movi_list); | |
525 end_tag(pb, avi->riff_start); | |
119 | 526 |
1676 | 527 file_size = url_ftell(pb); |
528 url_fseek(pb, avi->odml_list - 8, SEEK_SET); | |
529 put_tag(pb, "LIST"); /* Making this AVI OpenDML one */ | |
530 url_fskip(pb, 16); | |
0 | 531 |
1676 | 532 for (n=nb_frames=0;n<s->nb_streams;n++) { |
533 AVCodecContext *stream = s->streams[n]->codec; | |
534 if (stream->codec_type == CODEC_TYPE_VIDEO) { | |
535 if (nb_frames < avi->packet_count[n]) | |
536 nb_frames = avi->packet_count[n]; | |
537 } else { | |
538 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) { | |
539 nb_frames += avi->packet_count[n]; | |
540 } | |
0 | 541 } |
542 } | |
1676 | 543 put_le32(pb, nb_frames); |
544 url_fseek(pb, file_size, SEEK_SET); | |
545 | |
546 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
|
547 } |
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
|
548 } |
119 | 549 put_flush_packet(pb); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
550 |
119 | 551 for (i=0; i<MAX_STREAMS; i++) { |
887 | 552 for (j=0; j<avi->indexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) |
119 | 553 av_free(avi->indexes[i].cluster[j]); |
887 | 554 av_free(avi->indexes[i].cluster); |
555 avi->indexes[i].cluster = NULL; | |
556 avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0; | |
119 | 557 } |
885 | 558 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
559 return res; |
0 | 560 } |
561 | |
1169 | 562 AVOutputFormat avi_muxer = { |
0 | 563 "avi", |
564 "avi format", | |
565 "video/x-msvideo", | |
566 "avi", | |
567 sizeof(AVIContext), | |
568 CODEC_ID_MP2, | |
106
4da5d55b3690
we really shouldnt use M$* as default codec -> use MPEG4 as default
michaelni
parents:
105
diff
changeset
|
569 CODEC_ID_MPEG4, |
0 | 570 avi_write_header, |
571 avi_write_packet, | |
572 avi_write_trailer, | |
1679 | 573 .codec_tag= (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, 0}, |
0 | 574 }; |
1169 | 575 #endif //CONFIG_AVI_MUXER |