Mercurial > libavformat.hg
annotate avienc.c @ 1960:c0289552590f libavformat
Change the vhook code to send real timestamps to the filters instead of the
current time of day, which is useless, and which the filters could just as
easily query for themselves.
patch by Bobby Bingham, uhmmmm gmail com
author | diego |
---|---|
date | Thu, 29 Mar 2007 05:24:35 +0000 |
parents | ba58d49d4685 |
children | 8cf17fde9a1c |
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 { | |
108 ByteIOContext *pb = &s->pb; | |
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; | |
141 ByteIOContext *pb = &s->pb; | |
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 |
89
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
200 /* 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
|
201 if (! stream->codec_tag) { |
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
202 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
|
203 } |
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
204 |
0 | 205 /* stream generic header */ |
206 strh = start_tag(pb, "strh"); | |
207 switch(stream->codec_type) { | |
781 | 208 case CODEC_TYPE_VIDEO: put_tag(pb, "vids"); break; |
209 case CODEC_TYPE_AUDIO: put_tag(pb, "auds"); break; | |
210 // case CODEC_TYPE_TEXT : put_tag(pb, "txts"); break; | |
211 case CODEC_TYPE_DATA : put_tag(pb, "dats"); break; | |
212 } | |
213 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
89
8e3cf4e9fc5a
rawvideo patch by (Fred Rothganger <rothgang at uiuc dot edu>)
michaelni
parents:
85
diff
changeset
|
214 put_le32(pb, stream->codec_tag); |
781 | 215 else |
216 put_le32(pb, 1); | |
217 put_le32(pb, 0); /* flags */ | |
218 put_le16(pb, 0); /* priority */ | |
219 put_le16(pb, 0); /* language */ | |
220 put_le32(pb, 0); /* initial frame */ | |
221 | |
222 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
|
223 |
781 | 224 put_le32(pb, au_scale); /* scale */ |
225 put_le32(pb, au_byterate); /* rate */ | |
226 av_set_pts_info(s->streams[i], 64, au_scale, au_byterate); | |
227 | |
228 put_le32(pb, 0); /* start */ | |
229 avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ | |
887 | 230 if (url_is_streamed(pb)) |
231 put_le32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ | |
232 else | |
233 put_le32(pb, 0); /* length, XXX: filled later */ | |
885 | 234 |
781 | 235 /* suggested buffer size */ //FIXME set at the end to largest chunk |
236 if(stream->codec_type == CODEC_TYPE_VIDEO) | |
885 | 237 put_le32(pb, 1024 * 1024); |
781 | 238 else if(stream->codec_type == CODEC_TYPE_AUDIO) |
885 | 239 put_le32(pb, 12 * 1024); |
781 | 240 else |
885 | 241 put_le32(pb, 0); |
781 | 242 put_le32(pb, -1); /* quality */ |
243 put_le32(pb, au_ssize); /* sample size */ | |
244 put_le32(pb, 0); | |
245 put_le16(pb, stream->width); | |
246 put_le16(pb, stream->height); | |
0 | 247 end_tag(pb, strh); |
248 | |
781 | 249 if(stream->codec_type != CODEC_TYPE_DATA){ |
0 | 250 strf = start_tag(pb, "strf"); |
251 switch(stream->codec_type) { | |
252 case CODEC_TYPE_VIDEO: | |
887 | 253 put_bmp_header(pb, stream, codec_bmp_tags, 0); |
0 | 254 break; |
255 case CODEC_TYPE_AUDIO: | |
256 if (put_wav_header(pb, stream) < 0) { | |
257 av_free(avi); | |
258 return -1; | |
259 } | |
260 break; | |
261 default: | |
537 | 262 return -1; |
0 | 263 } |
264 end_tag(pb, strf); | |
781 | 265 } |
885 | 266 |
887 | 267 if (!url_is_streamed(pb)) { |
268 unsigned char tag[5]; | |
269 int j; | |
885 | 270 |
271 /* Starting to lay out AVI OpenDML master index. | |
887 | 272 * We want to make it JUNK entry for now, since we'd |
273 * like to get away without making AVI an OpenDML one | |
274 * for compatibility reasons. | |
275 */ | |
276 avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0; | |
277 avi->indexes[i].indx_start = start_tag(pb, "JUNK"); | |
278 put_le16(pb, 4); /* wLongsPerEntry */ | |
279 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ | |
280 put_byte(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ | |
281 put_le32(pb, 0); /* nEntriesInUse (will fill out later on) */ | |
282 put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type)); | |
283 /* dwChunkId */ | |
284 put_le64(pb, 0); /* dwReserved[3] | |
285 put_le32(pb, 0); Must be 0. */ | |
286 for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) | |
287 put_le64(pb, 0); | |
288 end_tag(pb, avi->indexes[i].indx_start); | |
289 } | |
885 | 290 |
0 | 291 end_tag(pb, list2); |
292 } | |
885 | 293 |
119 | 294 if (!url_is_streamed(pb)) { |
295 /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ | |
296 avi->odml_list = start_tag(pb, "JUNK"); | |
297 put_tag(pb, "odml"); | |
298 put_tag(pb, "dmlh"); | |
299 put_le32(pb, 248); | |
300 for (i = 0; i < 248; i+= 4) | |
301 put_le32(pb, 0); | |
302 end_tag(pb, avi->odml_list); | |
303 } | |
0 | 304 |
305 end_tag(pb, list1); | |
885 | 306 |
1256 | 307 list2 = start_tag(pb, "LIST"); |
308 put_tag(pb, "INFO"); | |
309 avi_write_info_tag(pb, "INAM", s->title); | |
310 avi_write_info_tag(pb, "IART", s->author); | |
311 avi_write_info_tag(pb, "ICOP", s->copyright); | |
312 avi_write_info_tag(pb, "ICMT", s->comment); | |
313 avi_write_info_tag(pb, "IPRD", s->album); | |
314 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
|
315 if (s->track) { |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
316 char str_track[4]; |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
317 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
|
318 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
|
319 } |
1256 | 320 if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) |
321 avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); | |
322 end_tag(pb, list2); | |
323 | |
324 /* some padding for easier tag editing */ | |
325 list2 = start_tag(pb, "JUNK"); | |
326 for (i = 0; i < 1016; i += 4) | |
327 put_le32(pb, 0); | |
328 end_tag(pb, list2); | |
329 | |
0 | 330 avi->movi_list = start_tag(pb, "LIST"); |
331 put_tag(pb, "movi"); | |
332 | |
333 put_flush_packet(pb); | |
334 | |
335 return 0; | |
336 } | |
337 | |
119 | 338 static int avi_write_ix(AVFormatContext *s) |
339 { | |
340 ByteIOContext *pb = &s->pb; | |
341 AVIContext *avi = s->priv_data; | |
1332 | 342 char tag[5]; |
343 char ix_tag[] = "ix00"; | |
119 | 344 int i, j; |
885 | 345 |
976 | 346 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
|
347 |
119 | 348 if (avi->riff_id > AVI_MASTER_INDEX_SIZE) |
349 return -1; | |
885 | 350 |
119 | 351 for (i=0;i<s->nb_streams;i++) { |
887 | 352 offset_t ix, pos; |
885 | 353 |
887 | 354 avi_stream2fourcc(&tag[0], i, s->streams[i]->codec->codec_type); |
355 ix_tag[3] = '0' + i; | |
885 | 356 |
887 | 357 /* Writing AVI OpenDML leaf index chunk */ |
358 ix = url_ftell(pb); | |
359 put_tag(pb, &ix_tag[0]); /* ix?? */ | |
360 put_le32(pb, avi->indexes[i].entry * 8 + 24); | |
361 /* chunk size */ | |
119 | 362 put_le16(pb, 2); /* wLongsPerEntry */ |
887 | 363 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ |
364 put_byte(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ | |
365 put_le32(pb, avi->indexes[i].entry); | |
366 /* nEntriesInUse */ | |
367 put_tag(pb, &tag[0]); /* dwChunkId */ | |
368 put_le64(pb, avi->movi_list);/* qwBaseOffset */ | |
369 put_le32(pb, 0); /* dwReserved_3 (must be 0) */ | |
119 | 370 |
371 for (j=0; j<avi->indexes[i].entry; j++) { | |
372 AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j); | |
887 | 373 put_le32(pb, ie->pos + 8); |
374 put_le32(pb, ((uint32_t)ie->len & ~0x80000000) | | |
375 (ie->flags & 0x10 ? 0 : 0x80000000)); | |
119 | 376 } |
887 | 377 put_flush_packet(pb); |
119 | 378 pos = url_ftell(pb); |
885 | 379 |
887 | 380 /* Updating one entry in the AVI OpenDML master index */ |
381 url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET); | |
382 put_tag(pb, "indx"); /* enabling this entry */ | |
383 url_fskip(pb, 8); | |
384 put_le32(pb, avi->riff_id); /* nEntriesInUse */ | |
385 url_fskip(pb, 16*avi->riff_id); | |
386 put_le64(pb, ix); /* qwOffset */ | |
387 put_le32(pb, pos - ix); /* dwSize */ | |
388 put_le32(pb, avi->indexes[i].entry); /* dwDuration */ | |
119 | 389 |
887 | 390 url_fseek(pb, pos, SEEK_SET); |
119 | 391 } |
392 return 0; | |
393 } | |
394 | |
395 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
|
396 { |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
397 ByteIOContext *pb = &s->pb; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
398 AVIContext *avi = s->priv_data; |
1267 | 399 offset_t idx_chunk; |
400 int i; | |
1332 | 401 char tag[5]; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
402 |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
403 if (!url_is_streamed(pb)) { |
887 | 404 AVIIentry* ie = 0, *tie; |
405 int entry[MAX_STREAMS]; | |
406 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
|
407 |
887 | 408 idx_chunk = start_tag(pb, "idx1"); |
409 memset(&entry[0], 0, sizeof(entry)); | |
410 do { | |
411 empty = 1; | |
412 for (i=0; i<s->nb_streams; i++) { | |
413 if (avi->indexes[i].entry <= entry[i]) | |
414 continue; | |
885 | 415 |
887 | 416 tie = avi_get_ientry(&avi->indexes[i], entry[i]); |
417 if (empty || tie->pos < ie->pos) { | |
418 ie = tie; | |
419 stream_id = i; | |
420 } | |
421 empty = 0; | |
422 } | |
423 if (!empty) { | |
424 avi_stream2fourcc(&tag[0], stream_id, | |
425 s->streams[stream_id]->codec->codec_type); | |
426 put_tag(pb, &tag[0]); | |
427 put_le32(pb, ie->flags); | |
119 | 428 put_le32(pb, ie->pos); |
429 put_le32(pb, ie->len); | |
887 | 430 entry[stream_id]++; |
431 } | |
432 } while (!empty); | |
433 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
|
434 |
1267 | 435 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
|
436 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
437 return 0; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
438 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
439 |
468 | 440 static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 441 { |
442 AVIContext *avi = s->priv_data; | |
443 ByteIOContext *pb = &s->pb; | |
444 unsigned char tag[5]; | |
468 | 445 unsigned int flags=0; |
446 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
|
447 AVCodecContext *enc= s->streams[stream_index]->codec; |
468 | 448 int size= pkt->size; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
449 |
1443
404048ea11bc
Replace most of the %lld and %llx by their (cleaner) PRI*64 counterparts.
diego
parents:
1415
diff
changeset
|
450 // av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index); |
724 | 451 while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){ |
479 | 452 AVPacket empty_packet; |
453 | |
454 av_init_packet(&empty_packet); | |
455 empty_packet.size= 0; | |
456 empty_packet.data= NULL; | |
457 empty_packet.stream_index= stream_index; | |
458 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
|
459 // av_log(s, AV_LOG_DEBUG, "dup %"PRId64" %d\n", pkt->dts, avi->packet_count[stream_index]); |
479 | 460 } |
461 avi->packet_count[stream_index]++; | |
462 | |
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
|
463 // Make sure to put an OpenDML chunk when the file size exceeds the limits |
885 | 464 if (!url_is_streamed(pb) && |
887 | 465 (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { |
885 | 466 |
119 | 467 avi_write_ix(s); |
468 end_tag(pb, avi->movi_list); | |
885 | 469 |
887 | 470 if (avi->riff_id == 1) |
471 avi_write_idx1(s); | |
119 | 472 |
887 | 473 end_tag(pb, avi->riff_start); |
474 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
|
475 } |
885 | 476 |
119 | 477 avi_stream2fourcc(&tag[0], stream_index, enc->codec_type); |
468 | 478 if(pkt->flags&PKT_FLAG_KEY) |
479 flags = 0x10; | |
119 | 480 if (enc->codec_type == CODEC_TYPE_AUDIO) { |
0 | 481 avi->audio_strm_length[stream_index] += size; |
468 | 482 } |
0 | 483 |
484 if (!url_is_streamed(&s->pb)) { | |
119 | 485 AVIIndex* idx = &avi->indexes[stream_index]; |
887 | 486 int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; |
487 int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; | |
119 | 488 if (idx->ents_allocated <= idx->entry) { |
887 | 489 idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); |
490 if (!idx->cluster) | |
491 return -1; | |
119 | 492 idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); |
887 | 493 if (!idx->cluster[cl]) |
494 return -1; | |
495 idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; | |
496 } | |
885 | 497 |
887 | 498 idx->cluster[cl][id].flags = flags; |
119 | 499 idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list; |
500 idx->cluster[cl][id].len = size; | |
887 | 501 idx->entry++; |
0 | 502 } |
885 | 503 |
0 | 504 put_buffer(pb, tag, 4); |
505 put_le32(pb, size); | |
468 | 506 put_buffer(pb, pkt->data, size); |
0 | 507 if (size & 1) |
508 put_byte(pb, 0); | |
509 | |
510 put_flush_packet(pb); | |
511 return 0; | |
512 } | |
513 | |
514 static int avi_write_trailer(AVFormatContext *s) | |
515 { | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
516 AVIContext *avi = s->priv_data; |
0 | 517 ByteIOContext *pb = &s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
518 int res = 0; |
119 | 519 int i, j, n, nb_frames; |
520 offset_t file_size; | |
0 | 521 |
1676 | 522 if (!url_is_streamed(pb)){ |
523 if (avi->riff_id == 1) { | |
524 end_tag(pb, avi->movi_list); | |
525 res = avi_write_idx1(s); | |
526 end_tag(pb, avi->riff_start); | |
527 } else { | |
528 avi_write_ix(s); | |
529 end_tag(pb, avi->movi_list); | |
530 end_tag(pb, avi->riff_start); | |
119 | 531 |
1676 | 532 file_size = url_ftell(pb); |
533 url_fseek(pb, avi->odml_list - 8, SEEK_SET); | |
534 put_tag(pb, "LIST"); /* Making this AVI OpenDML one */ | |
535 url_fskip(pb, 16); | |
0 | 536 |
1676 | 537 for (n=nb_frames=0;n<s->nb_streams;n++) { |
538 AVCodecContext *stream = s->streams[n]->codec; | |
539 if (stream->codec_type == CODEC_TYPE_VIDEO) { | |
540 if (nb_frames < avi->packet_count[n]) | |
541 nb_frames = avi->packet_count[n]; | |
542 } else { | |
543 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) { | |
544 nb_frames += avi->packet_count[n]; | |
545 } | |
0 | 546 } |
547 } | |
1676 | 548 put_le32(pb, nb_frames); |
549 url_fseek(pb, file_size, SEEK_SET); | |
550 | |
551 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
|
552 } |
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
|
553 } |
119 | 554 put_flush_packet(pb); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
555 |
119 | 556 for (i=0; i<MAX_STREAMS; i++) { |
887 | 557 for (j=0; j<avi->indexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) |
119 | 558 av_free(avi->indexes[i].cluster[j]); |
887 | 559 av_free(avi->indexes[i].cluster); |
560 avi->indexes[i].cluster = NULL; | |
561 avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0; | |
119 | 562 } |
885 | 563 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
564 return res; |
0 | 565 } |
566 | |
1169 | 567 AVOutputFormat avi_muxer = { |
0 | 568 "avi", |
569 "avi format", | |
570 "video/x-msvideo", | |
571 "avi", | |
572 sizeof(AVIContext), | |
573 CODEC_ID_MP2, | |
106
4da5d55b3690
we really shouldnt use M$* as default codec -> use MPEG4 as default
michaelni
parents:
105
diff
changeset
|
574 CODEC_ID_MPEG4, |
0 | 575 avi_write_header, |
576 avi_write_packet, | |
577 avi_write_trailer, | |
1679 | 578 .codec_tag= (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, 0}, |
0 | 579 }; |
1169 | 580 #endif //CONFIG_AVI_MUXER |