Mercurial > libavformat.hg
annotate swfenc.c @ 4723:a2390c6a35e6 libavformat
Fix index generation in the way that it was supposed to be used. See the
discussion in the ML thread "[PATCH] rmdec.c: merge old/new packet reading
code".
Over time, this code broke somewhat, e.g. seq was never actually written
into (and was thus always 1, therefore the seq condition was always true),
whereas it was supposed to be set to the sequence number of the video slice
in case the video frame is divided over multiple RM packets (slices). The
problem of this is that packets other than those containing the beginning
of a video frame would be indexed as well.
Secondly, flags&2 is supposed to be true for video keyframes and for these
audio packets containing the start of a block. For some codecs (e.g. AAC),
that is every single packet, whereas for others (e.g. cook), that is the
packet containing the first of a series of scrambled packets that are to be
descrambled together. Indexing any of the following would lead to incomplete
and thus useless frames. Problem here is that flags would be reset to 2 to
indicate that the first packet is ready to be returned, and in addition if
no data was left to be returned (which is always true for the first packet),
then we wouldn't actually write the index entry anyway.
All in all, the idea was good and it probably worked at some point, but that
is long ago. This patch should at the very least make it likely for this code
to be executed again at the right times, i.e. the way it was originally
intended to be used.
author | rbultje |
---|---|
date | Sun, 15 Mar 2009 20:14:25 +0000 |
parents | fc0a165de804 |
children | 7aa7c5853bb6 |
rev | line source |
---|---|
0 | 1 /* |
3356 | 2 * Flash Compatible Streaming Format muxer |
4251
77e0c7511d41
cosmetics: Remove pointless period after copyright statement non-sentences.
diego
parents:
4206
diff
changeset
|
3 * Copyright (c) 2000 Fabrice Bellard |
77e0c7511d41
cosmetics: Remove pointless period after copyright statement non-sentences.
diego
parents:
4206
diff
changeset
|
4 * Copyright (c) 2003 Tinic Uro |
0 | 5 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
6 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
7 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
8 * FFmpeg is free software; you can redistribute it and/or |
0 | 9 * modify it under the terms of the GNU Lesser General Public |
10 * 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:
1305
diff
changeset
|
11 * version 2.1 of the License, or (at your option) any later version. |
0 | 12 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1305
diff
changeset
|
13 * FFmpeg is distributed in the hope that it will be useful, |
0 | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 * Lesser General Public License for more details. | |
17 * | |
18 * 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:
1305
diff
changeset
|
19 * License along with FFmpeg; if not, write to the Free Software |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
887
diff
changeset
|
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 21 */ |
3286 | 22 |
23 #include "libavcodec/bitstream.h" | |
0 | 24 #include "avformat.h" |
3302 | 25 #include "swf.h" |
0 | 26 |
27 static void put_swf_tag(AVFormatContext *s, int tag) | |
28 { | |
29 SWFContext *swf = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
30 ByteIOContext *pb = s->pb; |
0 | 31 |
32 swf->tag_pos = url_ftell(pb); | |
33 swf->tag = tag; | |
34 /* reserve some room for the tag */ | |
35 if (tag & TAG_LONG) { | |
36 put_le16(pb, 0); | |
37 put_le32(pb, 0); | |
38 } else { | |
39 put_le16(pb, 0); | |
40 } | |
41 } | |
42 | |
43 static void put_swf_end_tag(AVFormatContext *s) | |
44 { | |
45 SWFContext *swf = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
46 ByteIOContext *pb = s->pb; |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3591
diff
changeset
|
47 int64_t pos; |
0 | 48 int tag_len, tag; |
49 | |
50 pos = url_ftell(pb); | |
51 tag_len = pos - swf->tag_pos - 2; | |
52 tag = swf->tag; | |
53 url_fseek(pb, swf->tag_pos, SEEK_SET); | |
54 if (tag & TAG_LONG) { | |
55 tag &= ~TAG_LONG; | |
56 put_le16(pb, (tag << 6) | 0x3f); | |
57 put_le32(pb, tag_len - 4); | |
58 } else { | |
59 assert(tag_len < 0x3f); | |
60 put_le16(pb, (tag << 6) | tag_len); | |
61 } | |
62 url_fseek(pb, pos, SEEK_SET); | |
63 } | |
64 | |
65 static inline void max_nbits(int *nbits_ptr, int val) | |
66 { | |
67 int n; | |
68 | |
69 if (val == 0) | |
70 return; | |
71 val = abs(val); | |
72 n = 1; | |
73 while (val != 0) { | |
74 n++; | |
75 val >>= 1; | |
76 } | |
77 if (n > *nbits_ptr) | |
78 *nbits_ptr = n; | |
79 } | |
80 | |
885 | 81 static void put_swf_rect(ByteIOContext *pb, |
0 | 82 int xmin, int xmax, int ymin, int ymax) |
83 { | |
84 PutBitContext p; | |
65 | 85 uint8_t buf[256]; |
0 | 86 int nbits, mask; |
87 | |
276 | 88 init_put_bits(&p, buf, sizeof(buf)); |
885 | 89 |
0 | 90 nbits = 0; |
91 max_nbits(&nbits, xmin); | |
92 max_nbits(&nbits, xmax); | |
93 max_nbits(&nbits, ymin); | |
94 max_nbits(&nbits, ymax); | |
95 mask = (1 << nbits) - 1; | |
96 | |
97 /* rectangle info */ | |
98 put_bits(&p, 5, nbits); | |
99 put_bits(&p, nbits, xmin & mask); | |
100 put_bits(&p, nbits, xmax & mask); | |
101 put_bits(&p, nbits, ymin & mask); | |
102 put_bits(&p, nbits, ymax & mask); | |
885 | 103 |
0 | 104 flush_put_bits(&p); |
105 put_buffer(pb, buf, pbBufPtr(&p) - p.buf); | |
106 } | |
107 | |
108 static void put_swf_line_edge(PutBitContext *pb, int dx, int dy) | |
109 { | |
110 int nbits, mask; | |
111 | |
112 put_bits(pb, 1, 1); /* edge */ | |
113 put_bits(pb, 1, 1); /* line select */ | |
114 nbits = 2; | |
115 max_nbits(&nbits, dx); | |
116 max_nbits(&nbits, dy); | |
117 | |
118 mask = (1 << nbits) - 1; | |
119 put_bits(pb, 4, nbits - 2); /* 16 bits precision */ | |
120 if (dx == 0) { | |
2308 | 121 put_bits(pb, 1, 0); |
122 put_bits(pb, 1, 1); | |
123 put_bits(pb, nbits, dy & mask); | |
0 | 124 } else if (dy == 0) { |
2308 | 125 put_bits(pb, 1, 0); |
126 put_bits(pb, 1, 0); | |
127 put_bits(pb, nbits, dx & mask); | |
0 | 128 } else { |
2308 | 129 put_bits(pb, 1, 1); |
130 put_bits(pb, nbits, dx & mask); | |
131 put_bits(pb, nbits, dy & mask); | |
0 | 132 } |
133 } | |
134 | |
135 #define FRAC_BITS 16 | |
136 | |
137 static void put_swf_matrix(ByteIOContext *pb, | |
138 int a, int b, int c, int d, int tx, int ty) | |
139 { | |
140 PutBitContext p; | |
65 | 141 uint8_t buf[256]; |
359 | 142 int nbits; |
0 | 143 |
276 | 144 init_put_bits(&p, buf, sizeof(buf)); |
885 | 145 |
0 | 146 put_bits(&p, 1, 1); /* a, d present */ |
359 | 147 nbits = 1; |
148 max_nbits(&nbits, a); | |
149 max_nbits(&nbits, d); | |
150 put_bits(&p, 5, nbits); /* nb bits */ | |
151 put_bits(&p, nbits, a); | |
152 put_bits(&p, nbits, d); | |
885 | 153 |
0 | 154 put_bits(&p, 1, 1); /* b, c present */ |
359 | 155 nbits = 1; |
156 max_nbits(&nbits, c); | |
157 max_nbits(&nbits, b); | |
158 put_bits(&p, 5, nbits); /* nb bits */ | |
159 put_bits(&p, nbits, c); | |
160 put_bits(&p, nbits, b); | |
0 | 161 |
359 | 162 nbits = 1; |
163 max_nbits(&nbits, tx); | |
164 max_nbits(&nbits, ty); | |
165 put_bits(&p, 5, nbits); /* nb bits */ | |
166 put_bits(&p, nbits, tx); | |
167 put_bits(&p, nbits, ty); | |
0 | 168 |
169 flush_put_bits(&p); | |
170 put_buffer(pb, buf, pbBufPtr(&p) - p.buf); | |
171 } | |
172 | |
173 static int swf_write_header(AVFormatContext *s) | |
174 { | |
1623 | 175 SWFContext *swf = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
176 ByteIOContext *pb = s->pb; |
0 | 177 PutBitContext p; |
65 | 178 uint8_t buf1[256]; |
85
25062c9b1f86
per context frame_rate_base, this should finally fix frame_rate related av sync issues
michaelni
parents:
65
diff
changeset
|
179 int i, width, height, rate, rate_base; |
3372 | 180 int version; |
0 | 181 |
359 | 182 swf->sound_samples = 0; |
183 swf->swf_frame_number = 0; | |
184 swf->video_frame_number = 0; | |
185 | |
0 | 186 for(i=0;i<s->nb_streams;i++) { |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
187 AVCodecContext *enc = s->streams[i]->codec; |
1854 | 188 if (enc->codec_type == CODEC_TYPE_AUDIO) { |
189 if (enc->codec_id == CODEC_ID_MP3) { | |
190 if (!enc->frame_size) { | |
191 av_log(s, AV_LOG_ERROR, "audio frame size not set\n"); | |
192 return -1; | |
193 } | |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
194 swf->audio_enc = enc; |
4669
d6eb19c43e99
Allocate AVFifoBuffer through the fifo API to reduce future API/ABI issues.
michael
parents:
4398
diff
changeset
|
195 swf->audio_fifo= av_fifo_alloc(AUDIO_FIFO_SIZE); |
1854 | 196 } else { |
1865 | 197 av_log(s, AV_LOG_ERROR, "SWF muxer only supports MP3\n"); |
1854 | 198 return -1; |
199 } | |
200 } else { | |
2309 | 201 if (enc->codec_id == CODEC_ID_VP6F || |
202 enc->codec_id == CODEC_ID_FLV1 || | |
203 enc->codec_id == CODEC_ID_MJPEG) { | |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
204 swf->video_enc = enc; |
359 | 205 } else { |
1865 | 206 av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n"); |
359 | 207 return -1; |
208 } | |
209 } | |
0 | 210 } |
211 | |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
212 if (!swf->video_enc) { |
2289 | 213 /* currently, cannot work correctly if audio only */ |
0 | 214 width = 320; |
215 height = 200; | |
85
25062c9b1f86
per context frame_rate_base, this should finally fix frame_rate related av sync issues
michaelni
parents:
65
diff
changeset
|
216 rate = 10; |
25062c9b1f86
per context frame_rate_base, this should finally fix frame_rate related av sync issues
michaelni
parents:
65
diff
changeset
|
217 rate_base= 1; |
0 | 218 } else { |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
219 width = swf->video_enc->width; |
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
220 height = swf->video_enc->height; |
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
221 rate = swf->video_enc->time_base.den; |
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
222 rate_base = swf->video_enc->time_base.num; |
0 | 223 } |
224 | |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
225 if (!swf->audio_enc) |
2309 | 226 swf->samples_per_frame = (44100. * rate_base) / rate; |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
227 else |
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
228 swf->samples_per_frame = (swf->audio_enc->sample_rate * rate_base) / rate; |
359 | 229 |
3372 | 230 put_tag(pb, "FWS"); |
2955
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
231 |
3372 | 232 if (!strcmp("avm2", s->oformat->name)) |
233 version = 9; | |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
234 else if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_VP6F) |
3372 | 235 version = 8; /* version 8 and above support VP6 codec */ |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
236 else if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_FLV1) |
3372 | 237 version = 6; /* version 6 and above support FLV1 codec */ |
3369 | 238 else |
3372 | 239 version = 4; /* version 4 for mpeg audio support */ |
240 put_byte(pb, version); | |
241 | |
885 | 242 put_le32(pb, DUMMY_FILE_SIZE); /* dummy size |
243 (will be patched if not streamed) */ | |
0 | 244 |
359 | 245 put_swf_rect(pb, 0, width * 20, 0, height * 20); |
85
25062c9b1f86
per context frame_rate_base, this should finally fix frame_rate related av sync issues
michaelni
parents:
65
diff
changeset
|
246 put_le16(pb, (rate * 256) / rate_base); /* frame rate */ |
0 | 247 swf->duration_pos = url_ftell(pb); |
85
25062c9b1f86
per context frame_rate_base, this should finally fix frame_rate related av sync issues
michaelni
parents:
65
diff
changeset
|
248 put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */ |
885 | 249 |
2955
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
250 /* avm2/swf v9 (also v8?) files require a file attribute tag */ |
3372 | 251 if (version == 9) { |
2955
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
252 put_swf_tag(s, TAG_FILEATTRIBUTES); |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
253 put_le32(pb, 1<<3); /* set ActionScript v3/AVM2 flag */ |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
254 put_swf_end_tag(s); |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
255 } |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
256 |
0 | 257 /* define a shape with the jpeg inside */ |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
258 if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_MJPEG) { |
359 | 259 put_swf_tag(s, TAG_DEFINESHAPE); |
0 | 260 |
359 | 261 put_le16(pb, SHAPE_ID); /* ID of shape */ |
262 /* bounding rectangle */ | |
263 put_swf_rect(pb, 0, width, 0, height); | |
264 /* style info */ | |
265 put_byte(pb, 1); /* one fill style */ | |
266 put_byte(pb, 0x41); /* clipped bitmap fill */ | |
267 put_le16(pb, BITMAP_ID); /* bitmap ID */ | |
268 /* position of the bitmap */ | |
885 | 269 put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0, |
2308 | 270 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0); |
359 | 271 put_byte(pb, 0); /* no line style */ |
885 | 272 |
359 | 273 /* shape drawing */ |
274 init_put_bits(&p, buf1, sizeof(buf1)); | |
275 put_bits(&p, 4, 1); /* one fill bit */ | |
276 put_bits(&p, 4, 0); /* zero line bit */ | |
885 | 277 |
359 | 278 put_bits(&p, 1, 0); /* not an edge */ |
279 put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0); | |
280 put_bits(&p, 5, 1); /* nbits */ | |
281 put_bits(&p, 1, 0); /* X */ | |
282 put_bits(&p, 1, 0); /* Y */ | |
283 put_bits(&p, 1, 1); /* set fill style 1 */ | |
885 | 284 |
359 | 285 /* draw the rectangle ! */ |
286 put_swf_line_edge(&p, width, 0); | |
287 put_swf_line_edge(&p, 0, height); | |
288 put_swf_line_edge(&p, -width, 0); | |
289 put_swf_line_edge(&p, 0, -height); | |
885 | 290 |
359 | 291 /* end of shape */ |
292 put_bits(&p, 1, 0); /* not an edge */ | |
293 put_bits(&p, 5, 0); | |
0 | 294 |
359 | 295 flush_put_bits(&p); |
296 put_buffer(pb, buf1, pbBufPtr(&p) - p.buf); | |
0 | 297 |
359 | 298 put_swf_end_tag(s); |
299 } | |
885 | 300 |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
301 if (swf->audio_enc && swf->audio_enc->codec_id == CODEC_ID_MP3) { |
3373 | 302 int v = 0; |
0 | 303 |
304 /* start sound */ | |
359 | 305 put_swf_tag(s, TAG_STREAMHEAD2); |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
306 switch(swf->audio_enc->sample_rate) { |
3374 | 307 case 11025: v |= 1 << 2; break; |
308 case 22050: v |= 2 << 2; break; | |
309 case 44100: v |= 3 << 2; break; | |
0 | 310 default: |
311 /* not supported */ | |
2164 | 312 av_log(s, AV_LOG_ERROR, "swf does not support that sample rate, choose from (44100, 22050, 11025).\n"); |
0 | 313 return -1; |
314 } | |
359 | 315 v |= 0x02; /* 16 bit playback */ |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
316 if (swf->audio_enc->channels == 2) |
359 | 317 v |= 0x01; /* stereo playback */ |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
318 put_byte(s->pb, v); |
0 | 319 v |= 0x20; /* mp3 compressed */ |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
320 put_byte(s->pb, v); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
321 put_le16(s->pb, swf->samples_per_frame); /* avg samples per frame */ |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
322 put_le16(s->pb, 0); |
885 | 323 |
0 | 324 put_swf_end_tag(s); |
325 } | |
326 | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
327 put_flush_packet(s->pb); |
0 | 328 return 0; |
329 } | |
330 | |
885 | 331 static int swf_write_video(AVFormatContext *s, |
241 | 332 AVCodecContext *enc, const uint8_t *buf, int size) |
0 | 333 { |
359 | 334 SWFContext *swf = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
335 ByteIOContext *pb = s->pb; |
885 | 336 |
359 | 337 /* Flash Player limit */ |
3369 | 338 if (swf->swf_frame_number == 16000) |
370
845f9de2c883
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
360
diff
changeset
|
339 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); |
0 | 340 |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
341 if (enc->codec_id == CODEC_ID_VP6F || |
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
342 enc->codec_id == CODEC_ID_FLV1) { |
2309 | 343 if (swf->video_frame_number == 0) { |
2308 | 344 /* create a new video object */ |
345 put_swf_tag(s, TAG_VIDEOSTREAM); | |
346 put_le16(pb, VIDEO_ID); | |
3591
aa6e8ff72d9e
update swf video frame number when muxing done, fix #439
bcoudurier
parents:
3424
diff
changeset
|
347 swf->vframes_pos = url_ftell(pb); |
2309 | 348 put_le16(pb, 15000); /* hard flash player limit */ |
2308 | 349 put_le16(pb, enc->width); |
350 put_le16(pb, enc->height); | |
351 put_byte(pb, 0); | |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
352 put_byte(pb,codec_get_tag(swf_codec_tags,enc->codec_id)); |
2308 | 353 put_swf_end_tag(s); |
885 | 354 |
2308 | 355 /* place the video object for the first time */ |
356 put_swf_tag(s, TAG_PLACEOBJECT2); | |
357 put_byte(pb, 0x36); | |
358 put_le16(pb, 1); | |
359 put_le16(pb, VIDEO_ID); | |
360 put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0); | |
2309 | 361 put_le16(pb, swf->video_frame_number); |
3370 | 362 put_tag(pb, "video"); |
2308 | 363 put_byte(pb, 0x00); |
364 put_swf_end_tag(s); | |
365 } else { | |
366 /* mark the character for update */ | |
367 put_swf_tag(s, TAG_PLACEOBJECT2); | |
368 put_byte(pb, 0x11); | |
369 put_le16(pb, 1); | |
2309 | 370 put_le16(pb, swf->video_frame_number); |
2308 | 371 put_swf_end_tag(s); |
372 } | |
885 | 373 |
2308 | 374 /* set video frame data */ |
375 put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG); | |
376 put_le16(pb, VIDEO_ID); | |
2309 | 377 put_le16(pb, swf->video_frame_number++); |
2308 | 378 put_buffer(pb, buf, size); |
379 put_swf_end_tag(s); | |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
380 } else if (enc->codec_id == CODEC_ID_MJPEG) { |
2308 | 381 if (swf->swf_frame_number > 0) { |
382 /* remove the shape */ | |
383 put_swf_tag(s, TAG_REMOVEOBJECT); | |
384 put_le16(pb, SHAPE_ID); /* shape ID */ | |
385 put_le16(pb, 1); /* depth */ | |
386 put_swf_end_tag(s); | |
885 | 387 |
2308 | 388 /* free the bitmap */ |
389 put_swf_tag(s, TAG_FREECHARACTER); | |
390 put_le16(pb, BITMAP_ID); | |
391 put_swf_end_tag(s); | |
392 } | |
885 | 393 |
2308 | 394 put_swf_tag(s, TAG_JPEG2 | TAG_LONG); |
885 | 395 |
2308 | 396 put_le16(pb, BITMAP_ID); /* ID of the image */ |
885 | 397 |
2308 | 398 /* a dummy jpeg header seems to be required */ |
3371 | 399 put_be32(pb, 0xffd8ffd9); |
2308 | 400 /* write the jpeg image */ |
401 put_buffer(pb, buf, size); | |
885 | 402 |
2308 | 403 put_swf_end_tag(s); |
885 | 404 |
2308 | 405 /* draw the shape */ |
885 | 406 |
2308 | 407 put_swf_tag(s, TAG_PLACEOBJECT); |
408 put_le16(pb, SHAPE_ID); /* shape ID */ | |
409 put_le16(pb, 1); /* depth */ | |
410 put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0); | |
411 put_swf_end_tag(s); | |
412 } | |
885 | 413 |
3381 | 414 swf->swf_frame_number++; |
0 | 415 |
359 | 416 /* streaming sound always should be placed just before showframe tags */ |
4669
d6eb19c43e99
Allocate AVFifoBuffer through the fifo API to reduce future API/ABI issues.
michael
parents:
4398
diff
changeset
|
417 if (swf->audio_enc && av_fifo_size(swf->audio_fifo)) { |
d6eb19c43e99
Allocate AVFifoBuffer through the fifo API to reduce future API/ABI issues.
michael
parents:
4398
diff
changeset
|
418 int frame_size = av_fifo_size(swf->audio_fifo); |
359 | 419 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG); |
1854 | 420 put_le16(pb, swf->sound_samples); |
421 put_le16(pb, 0); // seek samples | |
4689
fc0a165de804
Reorder arguments for av_fifo_generic_read to be more logical and
reimar
parents:
4669
diff
changeset
|
422 av_fifo_generic_read(swf->audio_fifo, pb, frame_size, &put_buffer); |
359 | 423 put_swf_end_tag(s); |
885 | 424 |
359 | 425 /* update FIFO */ |
1854 | 426 swf->sound_samples = 0; |
359 | 427 } |
428 | |
0 | 429 /* output the frame */ |
430 put_swf_tag(s, TAG_SHOWFRAME); | |
431 put_swf_end_tag(s); | |
885 | 432 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
433 put_flush_packet(s->pb); |
885 | 434 |
0 | 435 return 0; |
436 } | |
437 | |
885 | 438 static int swf_write_audio(AVFormatContext *s, |
4398
043d314bb216
Remove const qualifier from function argument to eliminate the warning
diego
parents:
4251
diff
changeset
|
439 AVCodecContext *enc, uint8_t *buf, int size) |
0 | 440 { |
359 | 441 SWFContext *swf = s->priv_data; |
442 | |
443 /* Flash Player limit */ | |
3369 | 444 if (swf->swf_frame_number == 16000) |
370
845f9de2c883
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
360
diff
changeset
|
445 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); |
0 | 446 |
4669
d6eb19c43e99
Allocate AVFifoBuffer through the fifo API to reduce future API/ABI issues.
michael
parents:
4398
diff
changeset
|
447 if (av_fifo_size(swf->audio_fifo) + size > AUDIO_FIFO_SIZE) { |
1854 | 448 av_log(s, AV_LOG_ERROR, "audio fifo too small to mux audio essence\n"); |
449 return -1; | |
359 | 450 } |
0 | 451 |
4669
d6eb19c43e99
Allocate AVFifoBuffer through the fifo API to reduce future API/ABI issues.
michael
parents:
4398
diff
changeset
|
452 av_fifo_generic_write(swf->audio_fifo, buf, size, NULL); |
1854 | 453 swf->sound_samples += enc->frame_size; |
454 | |
359 | 455 /* if audio only stream make sure we add swf frames */ |
3379
b3827117c786
simplify, use pointer to codec context in struct instead of only id
bcoudurier
parents:
3375
diff
changeset
|
456 if (!swf->video_enc) |
359 | 457 swf_write_video(s, enc, 0, 0); |
458 | |
0 | 459 return 0; |
460 } | |
461 | |
468 | 462 static int swf_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 463 { |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
807
diff
changeset
|
464 AVCodecContext *codec = s->streams[pkt->stream_index]->codec; |
0 | 465 if (codec->codec_type == CODEC_TYPE_AUDIO) |
468 | 466 return swf_write_audio(s, codec, pkt->data, pkt->size); |
0 | 467 else |
468 | 468 return swf_write_video(s, codec, pkt->data, pkt->size); |
0 | 469 } |
470 | |
471 static int swf_write_trailer(AVFormatContext *s) | |
472 { | |
473 SWFContext *swf = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
474 ByteIOContext *pb = s->pb; |
0 | 475 AVCodecContext *enc, *video_enc; |
476 int file_size, i; | |
477 | |
478 video_enc = NULL; | |
479 for(i=0;i<s->nb_streams;i++) { | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
807
diff
changeset
|
480 enc = s->streams[i]->codec; |
0 | 481 if (enc->codec_type == CODEC_TYPE_VIDEO) |
482 video_enc = enc; | |
3375 | 483 else |
4669
d6eb19c43e99
Allocate AVFifoBuffer through the fifo API to reduce future API/ABI issues.
michael
parents:
4398
diff
changeset
|
484 av_fifo_free(swf->audio_fifo); |
0 | 485 } |
486 | |
487 put_swf_tag(s, TAG_END); | |
488 put_swf_end_tag(s); | |
885 | 489 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
490 put_flush_packet(s->pb); |
0 | 491 |
492 /* patch file size and number of frames if not streamed */ | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2402
diff
changeset
|
493 if (!url_is_streamed(s->pb) && video_enc) { |
0 | 494 file_size = url_ftell(pb); |
495 url_fseek(pb, 4, SEEK_SET); | |
496 put_le32(pb, file_size); | |
497 url_fseek(pb, swf->duration_pos, SEEK_SET); | |
3382 | 498 put_le16(pb, swf->video_frame_number); |
3591
aa6e8ff72d9e
update swf video frame number when muxing done, fix #439
bcoudurier
parents:
3424
diff
changeset
|
499 url_fseek(pb, swf->vframes_pos, SEEK_SET); |
aa6e8ff72d9e
update swf video frame number when muxing done, fix #439
bcoudurier
parents:
3424
diff
changeset
|
500 put_le16(pb, swf->video_frame_number); |
1643
20c25a594c49
seek back at the end of file after updating header
bcoudurier
parents:
1642
diff
changeset
|
501 url_fseek(pb, file_size, SEEK_SET); |
0 | 502 } |
503 return 0; | |
504 } | |
505 | |
4206 | 506 #if CONFIG_SWF_MUXER |
1169 | 507 AVOutputFormat swf_muxer = { |
0 | 508 "swf", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3382
diff
changeset
|
509 NULL_IF_CONFIG_SMALL("Flash format"), |
0 | 510 "application/x-shockwave-flash", |
511 "swf", | |
512 sizeof(SWFContext), | |
359 | 513 CODEC_ID_MP3, |
514 CODEC_ID_FLV1, | |
0 | 515 swf_write_header, |
516 swf_write_packet, | |
517 swf_write_trailer, | |
518 }; | |
1169 | 519 #endif |
4206 | 520 #if CONFIG_AVM2_MUXER |
2955
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
521 AVOutputFormat avm2_muxer = { |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
522 "avm2", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3382
diff
changeset
|
523 NULL_IF_CONFIG_SMALL("Flash 9 (AVM2) format"), |
2955
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
524 "application/x-shockwave-flash", |
2959
1b7bf70aab74
unset extension, so code path, and guess format do not choose
bcoudurier
parents:
2955
diff
changeset
|
525 NULL, |
2955
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
526 sizeof(SWFContext), |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
527 CODEC_ID_MP3, |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
528 CODEC_ID_FLV1, |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
529 swf_write_header, |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
530 swf_write_packet, |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
531 swf_write_trailer, |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
532 }; |
b2d1cd7ab383
new avm2 (flash 9) muxer, patch by Paul Egan, paulegan at mail dot com
bcoudurier
parents:
2913
diff
changeset
|
533 #endif |