Mercurial > libavformat.hg
annotate avienc.c @ 3902:5f9bec099c69 libavformat
Add dynamic payload handlers to rdt.c. These follow the same API as the ones
in rtpdec.c, so that they can be shared and used in the same way in rtsp.c.
The handlers, since they are specific for RDT, are registered in rdt.c and
a new registration function is thus called from allformats.c.
The dynamic payload handler also implements RDT-specific SDP-line parsing for
OpaqueData and StartTime, which are specific for RDT and needed for proper
playback. OpaqueData contains one or a list ("MLTI") of "MDPR" chunks that
can be parsed by the rmdec.c function ff_rm_read_mdpr_codecdata(). To use
this function, we create a new rdt_demuxer, which has the same private data
as the rm_demuxer. The resulting AVFormatContext created with _open_stream()
can thus be used to call functions in the RM demuxer.
See discussion in "Realmedia patch" thread on ML.
author | rbultje |
---|---|
date | Sun, 07 Sep 2008 01:21:24 +0000 |
parents | b2977baec240 |
children | 549a09cf23fe |
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 return -1; | |
253 } | |
254 break; | |
255 default: | |
537 | 256 return -1; |
0 | 257 } |
258 end_tag(pb, strf); | |
781 | 259 } |
885 | 260 |
887 | 261 if (!url_is_streamed(pb)) { |
262 unsigned char tag[5]; | |
263 int j; | |
885 | 264 |
265 /* Starting to lay out AVI OpenDML master index. | |
887 | 266 * We want to make it JUNK entry for now, since we'd |
267 * like to get away without making AVI an OpenDML one | |
268 * for compatibility reasons. | |
269 */ | |
270 avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0; | |
271 avi->indexes[i].indx_start = start_tag(pb, "JUNK"); | |
272 put_le16(pb, 4); /* wLongsPerEntry */ | |
273 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ | |
274 put_byte(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ | |
275 put_le32(pb, 0); /* nEntriesInUse (will fill out later on) */ | |
276 put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type)); | |
277 /* dwChunkId */ | |
278 put_le64(pb, 0); /* dwReserved[3] | |
279 put_le32(pb, 0); Must be 0. */ | |
280 for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) | |
281 put_le64(pb, 0); | |
282 end_tag(pb, avi->indexes[i].indx_start); | |
283 } | |
885 | 284 |
3100 | 285 if( stream->codec_type == CODEC_TYPE_VIDEO |
3759
27537074f2a9
convert every muxer/demuxer to write/read sample_aspect_ratio from/to
aurel
parents:
3424
diff
changeset
|
286 && s->streams[i]->sample_aspect_ratio.num>0 |
27537074f2a9
convert every muxer/demuxer to write/read sample_aspect_ratio from/to
aurel
parents:
3424
diff
changeset
|
287 && s->streams[i]->sample_aspect_ratio.den>0){ |
3100 | 288 int vprp= start_tag(pb, "vprp"); |
3759
27537074f2a9
convert every muxer/demuxer to write/read sample_aspect_ratio from/to
aurel
parents:
3424
diff
changeset
|
289 AVRational dar = av_mul_q(s->streams[i]->sample_aspect_ratio, |
3100 | 290 (AVRational){stream->width, stream->height}); |
291 int num, den; | |
292 av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); | |
293 | |
294 put_le32(pb, 0); //video format = unknown | |
295 put_le32(pb, 0); //video standard= unknown | |
296 put_le32(pb, lrintf(1.0/av_q2d(stream->time_base))); | |
297 put_le32(pb, stream->width ); | |
298 put_le32(pb, stream->height); | |
3177 | 299 put_le16(pb, den); |
3100 | 300 put_le16(pb, num); |
301 put_le32(pb, stream->width ); | |
302 put_le32(pb, stream->height); | |
303 put_le32(pb, 1); //progressive FIXME | |
304 | |
305 put_le32(pb, stream->height); | |
306 put_le32(pb, stream->width ); | |
307 put_le32(pb, stream->height); | |
308 put_le32(pb, stream->width ); | |
309 put_le32(pb, 0); | |
310 put_le32(pb, 0); | |
311 | |
312 put_le32(pb, 0); | |
313 put_le32(pb, 0); | |
314 end_tag(pb, vprp); | |
315 } | |
316 | |
0 | 317 end_tag(pb, list2); |
318 } | |
885 | 319 |
119 | 320 if (!url_is_streamed(pb)) { |
321 /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ | |
322 avi->odml_list = start_tag(pb, "JUNK"); | |
323 put_tag(pb, "odml"); | |
324 put_tag(pb, "dmlh"); | |
325 put_le32(pb, 248); | |
326 for (i = 0; i < 248; i+= 4) | |
327 put_le32(pb, 0); | |
328 end_tag(pb, avi->odml_list); | |
329 } | |
0 | 330 |
331 end_tag(pb, list1); | |
885 | 332 |
1256 | 333 list2 = start_tag(pb, "LIST"); |
334 put_tag(pb, "INFO"); | |
335 avi_write_info_tag(pb, "INAM", s->title); | |
336 avi_write_info_tag(pb, "IART", s->author); | |
337 avi_write_info_tag(pb, "ICOP", s->copyright); | |
338 avi_write_info_tag(pb, "ICMT", s->comment); | |
339 avi_write_info_tag(pb, "IPRD", s->album); | |
340 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
|
341 if (s->track) { |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
342 char str_track[4]; |
f63d2066f478
Allow to store the the track number though the IPRT (part) tag in AVI.
gpoirier
parents:
1267
diff
changeset
|
343 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
|
344 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
|
345 } |
1256 | 346 if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) |
347 avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); | |
348 end_tag(pb, list2); | |
349 | |
350 /* some padding for easier tag editing */ | |
351 list2 = start_tag(pb, "JUNK"); | |
352 for (i = 0; i < 1016; i += 4) | |
353 put_le32(pb, 0); | |
354 end_tag(pb, list2); | |
355 | |
0 | 356 avi->movi_list = start_tag(pb, "LIST"); |
357 put_tag(pb, "movi"); | |
358 | |
359 put_flush_packet(pb); | |
360 | |
361 return 0; | |
362 } | |
363 | |
119 | 364 static int avi_write_ix(AVFormatContext *s) |
365 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
366 ByteIOContext *pb = s->pb; |
119 | 367 AVIContext *avi = s->priv_data; |
1332 | 368 char tag[5]; |
369 char ix_tag[] = "ix00"; | |
119 | 370 int i, j; |
885 | 371 |
976 | 372 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
|
373 |
119 | 374 if (avi->riff_id > AVI_MASTER_INDEX_SIZE) |
375 return -1; | |
885 | 376 |
119 | 377 for (i=0;i<s->nb_streams;i++) { |
887 | 378 offset_t ix, pos; |
885 | 379 |
887 | 380 avi_stream2fourcc(&tag[0], i, s->streams[i]->codec->codec_type); |
381 ix_tag[3] = '0' + i; | |
885 | 382 |
887 | 383 /* Writing AVI OpenDML leaf index chunk */ |
384 ix = url_ftell(pb); | |
385 put_tag(pb, &ix_tag[0]); /* ix?? */ | |
386 put_le32(pb, avi->indexes[i].entry * 8 + 24); | |
387 /* chunk size */ | |
119 | 388 put_le16(pb, 2); /* wLongsPerEntry */ |
887 | 389 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ |
390 put_byte(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ | |
391 put_le32(pb, avi->indexes[i].entry); | |
392 /* nEntriesInUse */ | |
393 put_tag(pb, &tag[0]); /* dwChunkId */ | |
394 put_le64(pb, avi->movi_list);/* qwBaseOffset */ | |
395 put_le32(pb, 0); /* dwReserved_3 (must be 0) */ | |
119 | 396 |
397 for (j=0; j<avi->indexes[i].entry; j++) { | |
398 AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j); | |
887 | 399 put_le32(pb, ie->pos + 8); |
400 put_le32(pb, ((uint32_t)ie->len & ~0x80000000) | | |
401 (ie->flags & 0x10 ? 0 : 0x80000000)); | |
119 | 402 } |
887 | 403 put_flush_packet(pb); |
119 | 404 pos = url_ftell(pb); |
885 | 405 |
887 | 406 /* Updating one entry in the AVI OpenDML master index */ |
407 url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET); | |
408 put_tag(pb, "indx"); /* enabling this entry */ | |
409 url_fskip(pb, 8); | |
410 put_le32(pb, avi->riff_id); /* nEntriesInUse */ | |
411 url_fskip(pb, 16*avi->riff_id); | |
412 put_le64(pb, ix); /* qwOffset */ | |
413 put_le32(pb, pos - ix); /* dwSize */ | |
414 put_le32(pb, avi->indexes[i].entry); /* dwDuration */ | |
119 | 415 |
887 | 416 url_fseek(pb, pos, SEEK_SET); |
119 | 417 } |
418 return 0; | |
419 } | |
420 | |
421 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
|
422 { |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
423 ByteIOContext *pb = s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
424 AVIContext *avi = s->priv_data; |
1267 | 425 offset_t idx_chunk; |
426 int i; | |
1332 | 427 char tag[5]; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
428 |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
429 if (!url_is_streamed(pb)) { |
887 | 430 AVIIentry* ie = 0, *tie; |
431 int entry[MAX_STREAMS]; | |
432 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
|
433 |
887 | 434 idx_chunk = start_tag(pb, "idx1"); |
435 memset(&entry[0], 0, sizeof(entry)); | |
436 do { | |
437 empty = 1; | |
438 for (i=0; i<s->nb_streams; i++) { | |
439 if (avi->indexes[i].entry <= entry[i]) | |
440 continue; | |
885 | 441 |
887 | 442 tie = avi_get_ientry(&avi->indexes[i], entry[i]); |
443 if (empty || tie->pos < ie->pos) { | |
444 ie = tie; | |
445 stream_id = i; | |
446 } | |
447 empty = 0; | |
448 } | |
449 if (!empty) { | |
450 avi_stream2fourcc(&tag[0], stream_id, | |
451 s->streams[stream_id]->codec->codec_type); | |
452 put_tag(pb, &tag[0]); | |
453 put_le32(pb, ie->flags); | |
119 | 454 put_le32(pb, ie->pos); |
455 put_le32(pb, ie->len); | |
887 | 456 entry[stream_id]++; |
457 } | |
458 } while (!empty); | |
459 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
|
460 |
1267 | 461 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
|
462 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
463 return 0; |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
464 } |
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
465 |
468 | 466 static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 467 { |
468 AVIContext *avi = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
469 ByteIOContext *pb = s->pb; |
0 | 470 unsigned char tag[5]; |
468 | 471 unsigned int flags=0; |
472 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
|
473 AVCodecContext *enc= s->streams[stream_index]->codec; |
468 | 474 int size= pkt->size; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
475 |
1443
404048ea11bc
Replace most of the %lld and %llx by their (cleaner) PRI*64 counterparts.
diego
parents:
1415
diff
changeset
|
476 // av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index); |
724 | 477 while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){ |
479 | 478 AVPacket empty_packet; |
479 | |
480 av_init_packet(&empty_packet); | |
481 empty_packet.size= 0; | |
482 empty_packet.data= NULL; | |
483 empty_packet.stream_index= stream_index; | |
484 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
|
485 // av_log(s, AV_LOG_DEBUG, "dup %"PRId64" %d\n", pkt->dts, avi->packet_count[stream_index]); |
479 | 486 } |
487 avi->packet_count[stream_index]++; | |
488 | |
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
|
489 // Make sure to put an OpenDML chunk when the file size exceeds the limits |
885 | 490 if (!url_is_streamed(pb) && |
887 | 491 (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { |
885 | 492 |
119 | 493 avi_write_ix(s); |
494 end_tag(pb, avi->movi_list); | |
885 | 495 |
887 | 496 if (avi->riff_id == 1) |
497 avi_write_idx1(s); | |
119 | 498 |
887 | 499 end_tag(pb, avi->riff_start); |
500 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
|
501 } |
885 | 502 |
119 | 503 avi_stream2fourcc(&tag[0], stream_index, enc->codec_type); |
468 | 504 if(pkt->flags&PKT_FLAG_KEY) |
505 flags = 0x10; | |
119 | 506 if (enc->codec_type == CODEC_TYPE_AUDIO) { |
0 | 507 avi->audio_strm_length[stream_index] += size; |
468 | 508 } |
0 | 509 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
510 if (!url_is_streamed(s->pb)) { |
119 | 511 AVIIndex* idx = &avi->indexes[stream_index]; |
887 | 512 int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; |
513 int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; | |
119 | 514 if (idx->ents_allocated <= idx->entry) { |
887 | 515 idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); |
516 if (!idx->cluster) | |
517 return -1; | |
119 | 518 idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); |
887 | 519 if (!idx->cluster[cl]) |
520 return -1; | |
521 idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; | |
522 } | |
885 | 523 |
887 | 524 idx->cluster[cl][id].flags = flags; |
119 | 525 idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list; |
526 idx->cluster[cl][id].len = size; | |
887 | 527 idx->entry++; |
0 | 528 } |
885 | 529 |
0 | 530 put_buffer(pb, tag, 4); |
531 put_le32(pb, size); | |
468 | 532 put_buffer(pb, pkt->data, size); |
0 | 533 if (size & 1) |
534 put_byte(pb, 0); | |
535 | |
536 put_flush_packet(pb); | |
537 return 0; | |
538 } | |
539 | |
540 static int avi_write_trailer(AVFormatContext *s) | |
541 { | |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
542 AVIContext *avi = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2227
diff
changeset
|
543 ByteIOContext *pb = s->pb; |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
544 int res = 0; |
119 | 545 int i, j, n, nb_frames; |
546 offset_t file_size; | |
0 | 547 |
1676 | 548 if (!url_is_streamed(pb)){ |
549 if (avi->riff_id == 1) { | |
550 end_tag(pb, avi->movi_list); | |
551 res = avi_write_idx1(s); | |
552 end_tag(pb, avi->riff_start); | |
553 } else { | |
554 avi_write_ix(s); | |
555 end_tag(pb, avi->movi_list); | |
556 end_tag(pb, avi->riff_start); | |
119 | 557 |
1676 | 558 file_size = url_ftell(pb); |
559 url_fseek(pb, avi->odml_list - 8, SEEK_SET); | |
560 put_tag(pb, "LIST"); /* Making this AVI OpenDML one */ | |
561 url_fskip(pb, 16); | |
0 | 562 |
1676 | 563 for (n=nb_frames=0;n<s->nb_streams;n++) { |
564 AVCodecContext *stream = s->streams[n]->codec; | |
565 if (stream->codec_type == CODEC_TYPE_VIDEO) { | |
566 if (nb_frames < avi->packet_count[n]) | |
567 nb_frames = avi->packet_count[n]; | |
568 } else { | |
569 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) { | |
570 nb_frames += avi->packet_count[n]; | |
571 } | |
0 | 572 } |
573 } | |
1676 | 574 put_le32(pb, nb_frames); |
575 url_fseek(pb, file_size, SEEK_SET); | |
576 | |
577 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
|
578 } |
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
|
579 } |
119 | 580 put_flush_packet(pb); |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
581 |
119 | 582 for (i=0; i<MAX_STREAMS; i++) { |
887 | 583 for (j=0; j<avi->indexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) |
119 | 584 av_free(avi->indexes[i].cluster[j]); |
887 | 585 av_free(avi->indexes[i].cluster); |
586 avi->indexes[i].cluster = NULL; | |
587 avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0; | |
119 | 588 } |
885 | 589 |
102
c48108fe538e
AVI > 2Gb (OpenDML) generation patch by (Roman Shaposhnick <rvs at sun dot com>)
michaelni
parents:
94
diff
changeset
|
590 return res; |
0 | 591 } |
592 | |
1169 | 593 AVOutputFormat avi_muxer = { |
0 | 594 "avi", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3177
diff
changeset
|
595 NULL_IF_CONFIG_SMALL("AVI format"), |
0 | 596 "video/x-msvideo", |
597 "avi", | |
598 sizeof(AVIContext), | |
599 CODEC_ID_MP2, | |
106
4da5d55b3690
we really shouldnt use M$* as default codec -> use MPEG4 as default
michaelni
parents:
105
diff
changeset
|
600 CODEC_ID_MPEG4, |
0 | 601 avi_write_header, |
602 avi_write_packet, | |
603 avi_write_trailer, | |
3766
f062deeedb8d
Change codec_tag type from const struct AVCodecTag ** to const struct AVCodecTag * const *
reimar
parents:
3759
diff
changeset
|
604 .codec_tag= (const AVCodecTag* const []){codec_bmp_tags, codec_wav_tags, 0}, |
0 | 605 }; |
1169 | 606 #endif //CONFIG_AVI_MUXER |