Mercurial > libavformat.hg
annotate rmenc.c @ 3754:8d267b43eaba libavformat
Move malloc() down until after all initializations, so that the resource is
only allocated if initialization worked. This means that on failure, we
don't have to deallocate it.
author | rbultje |
---|---|
date | Sat, 23 Aug 2008 18:46:30 +0000 |
parents | 8b4be8aa2324 |
children | f8a743bd2df8 |
rev | line source |
---|---|
0 | 1 /* |
2103 | 2 * "Real" compatible muxer. |
0 | 3 * Copyright (c) 2000, 2001 Fabrice Bellard. |
4 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1350
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1350
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1350
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:
1350
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:
1350
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:
1350
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:
888
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 20 */ |
21 #include "avformat.h" | |
2103 | 22 #include "rm.h" |
0 | 23 |
24 /* in ms */ | |
885 | 25 #define BUFFER_DURATION 0 |
0 | 26 |
27 | |
28 static void put_str(ByteIOContext *s, const char *tag) | |
29 { | |
30 put_be16(s,strlen(tag)); | |
31 while (*tag) { | |
32 put_byte(s, *tag++); | |
33 } | |
34 } | |
35 | |
36 static void put_str8(ByteIOContext *s, const char *tag) | |
37 { | |
38 put_byte(s, strlen(tag)); | |
39 while (*tag) { | |
40 put_byte(s, *tag++); | |
41 } | |
42 } | |
43 | |
885 | 44 static void rv10_write_header(AVFormatContext *ctx, |
0 | 45 int data_size, int index_pos) |
46 { | |
47 RMContext *rm = ctx->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2103
diff
changeset
|
48 ByteIOContext *s = ctx->pb; |
0 | 49 StreamInfo *stream; |
50 unsigned char *data_offset_ptr, *start_ptr; | |
51 const char *desc, *mimetype; | |
52 int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i; | |
53 int bit_rate, v, duration, flags, data_pos; | |
54 | |
55 start_ptr = s->buf_ptr; | |
56 | |
57 put_tag(s, ".RMF"); | |
58 put_be32(s,18); /* header size */ | |
59 put_be16(s,0); | |
60 put_be32(s,0); | |
61 put_be32(s,4 + ctx->nb_streams); /* num headers */ | |
62 | |
63 put_tag(s,"PROP"); | |
64 put_be32(s, 50); | |
65 put_be16(s, 0); | |
66 packet_max_size = 0; | |
67 packet_total_size = 0; | |
68 nb_packets = 0; | |
69 bit_rate = 0; | |
70 duration = 0; | |
71 for(i=0;i<ctx->nb_streams;i++) { | |
72 StreamInfo *stream = &rm->streams[i]; | |
73 bit_rate += stream->bit_rate; | |
74 if (stream->packet_max_size > packet_max_size) | |
75 packet_max_size = stream->packet_max_size; | |
76 nb_packets += stream->nb_packets; | |
77 packet_total_size += stream->packet_total_size; | |
78 /* select maximum duration */ | |
79 v = (int) (1000.0 * (float)stream->total_frames / stream->frame_rate); | |
80 if (v > duration) | |
81 duration = v; | |
82 } | |
83 put_be32(s, bit_rate); /* max bit rate */ | |
84 put_be32(s, bit_rate); /* avg bit rate */ | |
85 put_be32(s, packet_max_size); /* max packet size */ | |
86 if (nb_packets > 0) | |
87 packet_avg_size = packet_total_size / nb_packets; | |
88 else | |
89 packet_avg_size = 0; | |
90 put_be32(s, packet_avg_size); /* avg packet size */ | |
91 put_be32(s, nb_packets); /* num packets */ | |
92 put_be32(s, duration); /* duration */ | |
93 put_be32(s, BUFFER_DURATION); /* preroll */ | |
94 put_be32(s, index_pos); /* index offset */ | |
95 /* computation of data the data offset */ | |
96 data_offset_ptr = s->buf_ptr; | |
97 put_be32(s, 0); /* data offset : will be patched after */ | |
98 put_be16(s, ctx->nb_streams); /* num streams */ | |
99 flags = 1 | 2; /* save allowed & perfect play */ | |
100 if (url_is_streamed(s)) | |
101 flags |= 4; /* live broadcast */ | |
102 put_be16(s, flags); | |
885 | 103 |
0 | 104 /* comments */ |
105 | |
106 put_tag(s,"CONT"); | |
885 | 107 size = strlen(ctx->title) + strlen(ctx->author) + strlen(ctx->copyright) + |
0 | 108 strlen(ctx->comment) + 4 * 2 + 10; |
109 put_be32(s,size); | |
110 put_be16(s,0); | |
111 put_str(s, ctx->title); | |
112 put_str(s, ctx->author); | |
113 put_str(s, ctx->copyright); | |
114 put_str(s, ctx->comment); | |
885 | 115 |
0 | 116 for(i=0;i<ctx->nb_streams;i++) { |
117 int codec_data_size; | |
118 | |
119 stream = &rm->streams[i]; | |
885 | 120 |
0 | 121 if (stream->enc->codec_type == CODEC_TYPE_AUDIO) { |
122 desc = "The Audio Stream"; | |
123 mimetype = "audio/x-pn-realaudio"; | |
124 codec_data_size = 73; | |
125 } else { | |
126 desc = "The Video Stream"; | |
127 mimetype = "video/x-pn-realvideo"; | |
128 codec_data_size = 34; | |
129 } | |
130 | |
131 put_tag(s,"MDPR"); | |
132 size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size; | |
133 put_be32(s, size); | |
134 put_be16(s, 0); | |
135 | |
136 put_be16(s, i); /* stream number */ | |
137 put_be32(s, stream->bit_rate); /* max bit rate */ | |
138 put_be32(s, stream->bit_rate); /* avg bit rate */ | |
139 put_be32(s, stream->packet_max_size); /* max packet size */ | |
140 if (stream->nb_packets > 0) | |
885 | 141 packet_avg_size = stream->packet_total_size / |
0 | 142 stream->nb_packets; |
143 else | |
144 packet_avg_size = 0; | |
145 put_be32(s, packet_avg_size); /* avg packet size */ | |
146 put_be32(s, 0); /* start time */ | |
147 put_be32(s, BUFFER_DURATION); /* preroll */ | |
148 /* duration */ | |
149 if (url_is_streamed(s) || !stream->total_frames) | |
150 put_be32(s, (int)(3600 * 1000)); | |
151 else | |
152 put_be32(s, (int)(stream->total_frames * 1000 / stream->frame_rate)); | |
153 put_str8(s, desc); | |
154 put_str8(s, mimetype); | |
155 put_be32(s, codec_data_size); | |
885 | 156 |
0 | 157 if (stream->enc->codec_type == CODEC_TYPE_AUDIO) { |
158 int coded_frame_size, fscode, sample_rate; | |
159 sample_rate = stream->enc->sample_rate; | |
885 | 160 coded_frame_size = (stream->enc->bit_rate * |
0 | 161 stream->enc->frame_size) / (8 * sample_rate); |
162 /* audio codec info */ | |
163 put_tag(s, ".ra"); | |
164 put_byte(s, 0xfd); | |
165 put_be32(s, 0x00040000); /* version */ | |
166 put_tag(s, ".ra4"); | |
167 put_be32(s, 0x01b53530); /* stream length */ | |
168 put_be16(s, 4); /* unknown */ | |
169 put_be32(s, 0x39); /* header size */ | |
170 | |
171 switch(sample_rate) { | |
172 case 48000: | |
173 case 24000: | |
174 case 12000: | |
175 fscode = 1; | |
176 break; | |
177 default: | |
178 case 44100: | |
179 case 22050: | |
180 case 11025: | |
181 fscode = 2; | |
182 break; | |
183 case 32000: | |
184 case 16000: | |
185 case 8000: | |
186 fscode = 3; | |
187 } | |
3624
8b4be8aa2324
cosmetics: make all references to AC-3 capitalized and hyphenated
jbr
parents:
3424
diff
changeset
|
188 put_be16(s, fscode); /* codec additional info, for AC-3, seems |
0 | 189 to be a frequency code */ |
190 /* special hack to compensate rounding errors... */ | |
191 if (coded_frame_size == 557) | |
192 coded_frame_size--; | |
193 put_be32(s, coded_frame_size); /* frame length */ | |
194 put_be32(s, 0x51540); /* unknown */ | |
195 put_be32(s, 0x249f0); /* unknown */ | |
196 put_be32(s, 0x249f0); /* unknown */ | |
197 put_be16(s, 0x01); | |
198 /* frame length : seems to be very important */ | |
885 | 199 put_be16(s, coded_frame_size); |
0 | 200 put_be32(s, 0); /* unknown */ |
201 put_be16(s, stream->enc->sample_rate); /* sample rate */ | |
202 put_be32(s, 0x10); /* unknown */ | |
203 put_be16(s, stream->enc->channels); | |
204 put_str8(s, "Int0"); /* codec name */ | |
205 put_str8(s, "dnet"); /* codec name */ | |
206 put_be16(s, 0); /* title length */ | |
207 put_be16(s, 0); /* author length */ | |
208 put_be16(s, 0); /* copyright length */ | |
209 put_byte(s, 0); /* end of header */ | |
210 } else { | |
211 /* video codec info */ | |
212 put_be32(s,34); /* size */ | |
614 | 213 if(stream->enc->codec_id == CODEC_ID_RV10) |
214 put_tag(s,"VIDORV10"); | |
215 else | |
216 put_tag(s,"VIDORV20"); | |
0 | 217 put_be16(s, stream->enc->width); |
218 put_be16(s, stream->enc->height); | |
219 put_be16(s, (int) stream->frame_rate); /* frames per seconds ? */ | |
220 put_be32(s,0); /* unknown meaning */ | |
221 put_be16(s, (int) stream->frame_rate); /* unknown meaning */ | |
222 put_be32(s,0); /* unknown meaning */ | |
223 put_be16(s, 8); /* unknown meaning */ | |
224 /* Seems to be the codec version: only use basic H263. The next | |
225 versions seems to add a diffential DC coding as in | |
226 MPEG... nothing new under the sun */ | |
614 | 227 if(stream->enc->codec_id == CODEC_ID_RV10) |
885 | 228 put_be32(s,0x10000000); |
614 | 229 else |
885 | 230 put_be32(s,0x20103001); |
231 //put_be32(s,0x10003000); | |
0 | 232 } |
233 } | |
234 | |
235 /* patch data offset field */ | |
236 data_pos = s->buf_ptr - start_ptr; | |
237 rm->data_pos = data_pos; | |
238 data_offset_ptr[0] = data_pos >> 24; | |
239 data_offset_ptr[1] = data_pos >> 16; | |
240 data_offset_ptr[2] = data_pos >> 8; | |
241 data_offset_ptr[3] = data_pos; | |
885 | 242 |
0 | 243 /* data stream */ |
244 put_tag(s,"DATA"); | |
245 put_be32(s,data_size + 10 + 8); | |
246 put_be16(s,0); | |
247 | |
248 put_be32(s, nb_packets); /* number of packets */ | |
249 put_be32(s,0); /* next data header */ | |
250 } | |
251 | |
885 | 252 static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream, |
0 | 253 int length, int key_frame) |
254 { | |
255 int timestamp; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2103
diff
changeset
|
256 ByteIOContext *s = ctx->pb; |
0 | 257 |
258 stream->nb_packets++; | |
259 stream->packet_total_size += length; | |
260 if (length > stream->packet_max_size) | |
261 stream->packet_max_size = length; | |
262 | |
263 put_be16(s,0); /* version */ | |
264 put_be16(s,length + 12); | |
265 put_be16(s, stream->num); /* stream number */ | |
266 timestamp = (1000 * (float)stream->nb_frames) / stream->frame_rate; | |
267 put_be32(s, timestamp); /* timestamp */ | |
268 put_byte(s, 0); /* reserved */ | |
269 put_byte(s, key_frame ? 2 : 0); /* flags */ | |
270 } | |
271 | |
272 static int rm_write_header(AVFormatContext *s) | |
273 { | |
274 RMContext *rm = s->priv_data; | |
275 StreamInfo *stream; | |
276 int n; | |
277 AVCodecContext *codec; | |
278 | |
279 for(n=0;n<s->nb_streams;n++) { | |
280 s->streams[n]->id = n; | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
281 codec = s->streams[n]->codec; |
0 | 282 stream = &rm->streams[n]; |
283 memset(stream, 0, sizeof(StreamInfo)); | |
284 stream->num = n; | |
285 stream->bit_rate = codec->bit_rate; | |
286 stream->enc = codec; | |
287 | |
288 switch(codec->codec_type) { | |
289 case CODEC_TYPE_AUDIO: | |
290 rm->audio_stream = stream; | |
291 stream->frame_rate = (float)codec->sample_rate / (float)codec->frame_size; | |
292 /* XXX: dummy values */ | |
293 stream->packet_max_size = 1024; | |
294 stream->nb_packets = 0; | |
295 stream->total_frames = stream->nb_packets; | |
296 break; | |
297 case CODEC_TYPE_VIDEO: | |
298 rm->video_stream = stream; | |
743 | 299 stream->frame_rate = (float)codec->time_base.den / (float)codec->time_base.num; |
0 | 300 /* XXX: dummy values */ |
301 stream->packet_max_size = 4096; | |
302 stream->nb_packets = 0; | |
303 stream->total_frames = stream->nb_packets; | |
304 break; | |
305 default: | |
537 | 306 return -1; |
0 | 307 } |
308 } | |
309 | |
310 rv10_write_header(s, 0, 0); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2103
diff
changeset
|
311 put_flush_packet(s->pb); |
0 | 312 return 0; |
313 } | |
314 | |
470 | 315 static int rm_write_audio(AVFormatContext *s, const uint8_t *buf, int size, int flags) |
0 | 316 { |
65 | 317 uint8_t *buf1; |
0 | 318 RMContext *rm = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2103
diff
changeset
|
319 ByteIOContext *pb = s->pb; |
0 | 320 StreamInfo *stream = rm->audio_stream; |
321 int i; | |
322 | |
323 /* XXX: suppress this malloc */ | |
65 | 324 buf1= (uint8_t*) av_malloc( size * sizeof(uint8_t) ); |
885 | 325 |
470 | 326 write_packet_header(s, stream, size, !!(flags & PKT_FLAG_KEY)); |
885 | 327 |
3624
8b4be8aa2324
cosmetics: make all references to AC-3 capitalized and hyphenated
jbr
parents:
3424
diff
changeset
|
328 /* for AC-3, the words seem to be reversed */ |
0 | 329 for(i=0;i<size;i+=2) { |
330 buf1[i] = buf[i+1]; | |
331 buf1[i+1] = buf[i]; | |
332 } | |
333 put_buffer(pb, buf1, size); | |
334 put_flush_packet(pb); | |
335 stream->nb_frames++; | |
336 av_free(buf1); | |
337 return 0; | |
338 } | |
339 | |
470 | 340 static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int flags) |
0 | 341 { |
342 RMContext *rm = s->priv_data; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2103
diff
changeset
|
343 ByteIOContext *pb = s->pb; |
0 | 344 StreamInfo *stream = rm->video_stream; |
470 | 345 int key_frame = !!(flags & PKT_FLAG_KEY); |
0 | 346 |
347 /* XXX: this is incorrect: should be a parameter */ | |
348 | |
349 /* Well, I spent some time finding the meaning of these bits. I am | |
350 not sure I understood everything, but it works !! */ | |
351 #if 1 | |
2792
e0a046abae56
Fix muxer so that generated files are playable by realplayer, other open
rtogni
parents:
2771
diff
changeset
|
352 write_packet_header(s, stream, size + 7 + (size >= 0x4000)*4, key_frame); |
0 | 353 /* bit 7: '1' if final packet of a frame converted in several packets */ |
885 | 354 put_byte(pb, 0x81); |
0 | 355 /* bit 7: '1' if I frame. bits 6..0 : sequence number in current |
356 frame starting from 1 */ | |
357 if (key_frame) { | |
885 | 358 put_byte(pb, 0x81); |
0 | 359 } else { |
885 | 360 put_byte(pb, 0x01); |
0 | 361 } |
2792
e0a046abae56
Fix muxer so that generated files are playable by realplayer, other open
rtogni
parents:
2771
diff
changeset
|
362 if(size >= 0x4000){ |
e0a046abae56
Fix muxer so that generated files are playable by realplayer, other open
rtogni
parents:
2771
diff
changeset
|
363 put_be32(pb, size); /* total frame size */ |
e0a046abae56
Fix muxer so that generated files are playable by realplayer, other open
rtogni
parents:
2771
diff
changeset
|
364 put_be32(pb, size); /* offset from the start or the end */ |
e0a046abae56
Fix muxer so that generated files are playable by realplayer, other open
rtogni
parents:
2771
diff
changeset
|
365 }else{ |
e0a046abae56
Fix muxer so that generated files are playable by realplayer, other open
rtogni
parents:
2771
diff
changeset
|
366 put_be16(pb, 0x4000 | size); /* total frame size */ |
e0a046abae56
Fix muxer so that generated files are playable by realplayer, other open
rtogni
parents:
2771
diff
changeset
|
367 put_be16(pb, 0x4000 | size); /* offset from the start or the end */ |
e0a046abae56
Fix muxer so that generated files are playable by realplayer, other open
rtogni
parents:
2771
diff
changeset
|
368 } |
0 | 369 #else |
370 /* full frame */ | |
371 write_packet_header(s, size + 6); | |
885 | 372 put_byte(pb, 0xc0); |
611 | 373 put_be16(pb, 0x4000 + size); /* total frame size */ |
0 | 374 put_be16(pb, 0x4000 + packet_number * 126); /* position in stream */ |
375 #endif | |
885 | 376 put_byte(pb, stream->nb_frames & 0xff); |
377 | |
0 | 378 put_buffer(pb, buf, size); |
379 put_flush_packet(pb); | |
380 | |
381 stream->nb_frames++; | |
382 return 0; | |
383 } | |
384 | |
468 | 385 static int rm_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 386 { |
885 | 387 if (s->streams[pkt->stream_index]->codec->codec_type == |
0 | 388 CODEC_TYPE_AUDIO) |
470 | 389 return rm_write_audio(s, pkt->data, pkt->size, pkt->flags); |
0 | 390 else |
470 | 391 return rm_write_video(s, pkt->data, pkt->size, pkt->flags); |
0 | 392 } |
885 | 393 |
0 | 394 static int rm_write_trailer(AVFormatContext *s) |
395 { | |
396 RMContext *rm = s->priv_data; | |
397 int data_size, index_pos, i; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2103
diff
changeset
|
398 ByteIOContext *pb = s->pb; |
0 | 399 |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2103
diff
changeset
|
400 if (!url_is_streamed(s->pb)) { |
0 | 401 /* end of file: finish to write header */ |
402 index_pos = url_fseek(pb, 0, SEEK_CUR); | |
403 data_size = index_pos - rm->data_pos; | |
404 | |
405 /* index */ | |
406 put_tag(pb, "INDX"); | |
407 put_be32(pb, 10 + 10 * s->nb_streams); | |
408 put_be16(pb, 0); | |
885 | 409 |
0 | 410 for(i=0;i<s->nb_streams;i++) { |
3365 | 411 put_be32(pb, 0); /* zero indexes */ |
0 | 412 put_be16(pb, i); /* stream number */ |
413 put_be32(pb, 0); /* next index */ | |
414 } | |
415 /* undocumented end header */ | |
416 put_be32(pb, 0); | |
417 put_be32(pb, 0); | |
885 | 418 |
0 | 419 url_fseek(pb, 0, SEEK_SET); |
420 for(i=0;i<s->nb_streams;i++) | |
421 rm->streams[i].total_frames = rm->streams[i].nb_frames; | |
422 rv10_write_header(s, data_size, index_pos); | |
423 } else { | |
424 /* undocumented end header */ | |
425 put_be32(pb, 0); | |
426 put_be32(pb, 0); | |
427 } | |
428 put_flush_packet(pb); | |
429 return 0; | |
430 } | |
613 | 431 |
885 | 432 |
1169 | 433 AVOutputFormat rm_muxer = { |
0 | 434 "rm", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3365
diff
changeset
|
435 NULL_IF_CONFIG_SMALL("RM format"), |
14
b167760cd0aa
mimetype fixes patch by (Ryutaroh Matsumoto <ryutaroh at it dot ss dot titech dot ac dot jp>)
michaelni
parents:
7
diff
changeset
|
436 "application/vnd.rn-realmedia", |
0 | 437 "rm,ra", |
438 sizeof(RMContext), | |
439 CODEC_ID_AC3, | |
440 CODEC_ID_RV10, | |
441 rm_write_header, | |
442 rm_write_packet, | |
443 rm_write_trailer, | |
444 }; |