blob: f9821d18754c1d09295e75fd41cfbf78d5b22654
1 | /* |
2 | * "Real" compatible muxer. |
3 | * Copyright (c) 2000, 2001 Fabrice Bellard |
4 | * |
5 | * This file is part of FFmpeg. |
6 | * |
7 | * FFmpeg is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * FFmpeg is distributed in the hope that it will be useful, |
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 |
18 | * License along with FFmpeg; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | */ |
21 | #include "avformat.h" |
22 | #include "avio_internal.h" |
23 | #include "rm.h" |
24 | #include "libavutil/dict.h" |
25 | |
26 | typedef struct StreamInfo { |
27 | int nb_packets; |
28 | int packet_total_size; |
29 | int packet_max_size; |
30 | /* codec related output */ |
31 | int bit_rate; |
32 | AVRational frame_rate; |
33 | int nb_frames; /* current frame number */ |
34 | int total_frames; /* total number of frames */ |
35 | int num; |
36 | AVCodecParameters *par; |
37 | } StreamInfo; |
38 | |
39 | typedef struct RMMuxContext { |
40 | StreamInfo streams[2]; |
41 | StreamInfo *audio_stream, *video_stream; |
42 | int data_pos; /* position of the data after the header */ |
43 | } RMMuxContext; |
44 | |
45 | /* in ms */ |
46 | #define BUFFER_DURATION 0 |
47 | /* the header needs at most 7 + 4 + 12 B */ |
48 | #define MAX_HEADER_SIZE (7 + 4 + 12) |
49 | /* UINT16_MAX is the maximal chunk size */ |
50 | #define MAX_PACKET_SIZE (UINT16_MAX - MAX_HEADER_SIZE) |
51 | |
52 | |
53 | static void put_str(AVIOContext *s, const char *tag) |
54 | { |
55 | avio_wb16(s,strlen(tag)); |
56 | while (*tag) { |
57 | avio_w8(s, *tag++); |
58 | } |
59 | } |
60 | |
61 | static void put_str8(AVIOContext *s, const char *tag) |
62 | { |
63 | avio_w8(s, strlen(tag)); |
64 | while (*tag) { |
65 | avio_w8(s, *tag++); |
66 | } |
67 | } |
68 | |
69 | static int rv10_write_header(AVFormatContext *ctx, |
70 | int data_size, int index_pos) |
71 | { |
72 | RMMuxContext *rm = ctx->priv_data; |
73 | AVIOContext *s = ctx->pb; |
74 | StreamInfo *stream; |
75 | unsigned char *data_offset_ptr, *start_ptr; |
76 | const char *desc, *mimetype; |
77 | int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i; |
78 | int bit_rate, v, duration, flags, data_pos; |
79 | AVDictionaryEntry *tag; |
80 | |
81 | start_ptr = s->buf_ptr; |
82 | |
83 | ffio_wfourcc(s, ".RMF"); |
84 | avio_wb32(s,18); /* header size */ |
85 | avio_wb16(s,0); |
86 | avio_wb32(s,0); |
87 | avio_wb32(s,4 + ctx->nb_streams); /* num headers */ |
88 | |
89 | ffio_wfourcc(s,"PROP"); |
90 | avio_wb32(s, 50); |
91 | avio_wb16(s, 0); |
92 | packet_max_size = 0; |
93 | packet_total_size = 0; |
94 | nb_packets = 0; |
95 | bit_rate = 0; |
96 | duration = 0; |
97 | for(i=0;i<ctx->nb_streams;i++) { |
98 | StreamInfo *stream = &rm->streams[i]; |
99 | bit_rate += stream->bit_rate; |
100 | if (stream->packet_max_size > packet_max_size) |
101 | packet_max_size = stream->packet_max_size; |
102 | nb_packets += stream->nb_packets; |
103 | packet_total_size += stream->packet_total_size; |
104 | /* select maximum duration */ |
105 | v = av_rescale_q_rnd(stream->total_frames, (AVRational){1000, 1}, stream->frame_rate, AV_ROUND_ZERO); |
106 | if (v > duration) |
107 | duration = v; |
108 | } |
109 | avio_wb32(s, bit_rate); /* max bit rate */ |
110 | avio_wb32(s, bit_rate); /* avg bit rate */ |
111 | avio_wb32(s, packet_max_size); /* max packet size */ |
112 | if (nb_packets > 0) |
113 | packet_avg_size = packet_total_size / nb_packets; |
114 | else |
115 | packet_avg_size = 0; |
116 | avio_wb32(s, packet_avg_size); /* avg packet size */ |
117 | avio_wb32(s, nb_packets); /* num packets */ |
118 | avio_wb32(s, duration); /* duration */ |
119 | avio_wb32(s, BUFFER_DURATION); /* preroll */ |
120 | avio_wb32(s, index_pos); /* index offset */ |
121 | /* computation of data the data offset */ |
122 | data_offset_ptr = s->buf_ptr; |
123 | avio_wb32(s, 0); /* data offset : will be patched after */ |
124 | avio_wb16(s, ctx->nb_streams); /* num streams */ |
125 | flags = 1 | 2; /* save allowed & perfect play */ |
126 | if (!(s->seekable & AVIO_SEEKABLE_NORMAL)) |
127 | flags |= 4; /* live broadcast */ |
128 | avio_wb16(s, flags); |
129 | |
130 | /* comments */ |
131 | |
132 | ffio_wfourcc(s,"CONT"); |
133 | size = 4 * 2 + 10; |
134 | for(i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) { |
135 | tag = av_dict_get(ctx->metadata, ff_rm_metadata[i], NULL, 0); |
136 | if(tag) size += strlen(tag->value); |
137 | } |
138 | avio_wb32(s,size); |
139 | avio_wb16(s,0); |
140 | for(i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) { |
141 | tag = av_dict_get(ctx->metadata, ff_rm_metadata[i], NULL, 0); |
142 | put_str(s, tag ? tag->value : ""); |
143 | } |
144 | |
145 | for(i=0;i<ctx->nb_streams;i++) { |
146 | int codec_data_size; |
147 | |
148 | stream = &rm->streams[i]; |
149 | |
150 | if (stream->par->codec_type == AVMEDIA_TYPE_AUDIO) { |
151 | desc = "The Audio Stream"; |
152 | mimetype = "audio/x-pn-realaudio"; |
153 | codec_data_size = 73; |
154 | } else { |
155 | desc = "The Video Stream"; |
156 | mimetype = "video/x-pn-realvideo"; |
157 | codec_data_size = 34; |
158 | } |
159 | |
160 | ffio_wfourcc(s,"MDPR"); |
161 | size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size; |
162 | avio_wb32(s, size); |
163 | avio_wb16(s, 0); |
164 | |
165 | avio_wb16(s, i); /* stream number */ |
166 | avio_wb32(s, stream->bit_rate); /* max bit rate */ |
167 | avio_wb32(s, stream->bit_rate); /* avg bit rate */ |
168 | avio_wb32(s, stream->packet_max_size); /* max packet size */ |
169 | if (stream->nb_packets > 0) |
170 | packet_avg_size = stream->packet_total_size / |
171 | stream->nb_packets; |
172 | else |
173 | packet_avg_size = 0; |
174 | avio_wb32(s, packet_avg_size); /* avg packet size */ |
175 | avio_wb32(s, 0); /* start time */ |
176 | avio_wb32(s, BUFFER_DURATION); /* preroll */ |
177 | /* duration */ |
178 | if (!(s->seekable & AVIO_SEEKABLE_NORMAL) || !stream->total_frames) |
179 | avio_wb32(s, (int)(3600 * 1000)); |
180 | else |
181 | avio_wb32(s, av_rescale_q_rnd(stream->total_frames, (AVRational){1000, 1}, stream->frame_rate, AV_ROUND_ZERO)); |
182 | put_str8(s, desc); |
183 | put_str8(s, mimetype); |
184 | avio_wb32(s, codec_data_size); |
185 | |
186 | if (stream->par->codec_type == AVMEDIA_TYPE_AUDIO) { |
187 | int coded_frame_size, fscode, sample_rate; |
188 | int frame_size = av_get_audio_frame_duration2(stream->par, 0); |
189 | sample_rate = stream->par->sample_rate; |
190 | coded_frame_size = (stream->par->bit_rate * |
191 | frame_size) / (8 * sample_rate); |
192 | /* audio codec info */ |
193 | avio_write(s, ".ra", 3); |
194 | avio_w8(s, 0xfd); |
195 | avio_wb32(s, 0x00040000); /* version */ |
196 | ffio_wfourcc(s, ".ra4"); |
197 | avio_wb32(s, 0x01b53530); /* stream length */ |
198 | avio_wb16(s, 4); /* unknown */ |
199 | avio_wb32(s, 0x39); /* header size */ |
200 | |
201 | switch(sample_rate) { |
202 | case 48000: |
203 | case 24000: |
204 | case 12000: |
205 | fscode = 1; |
206 | break; |
207 | default: |
208 | case 44100: |
209 | case 22050: |
210 | case 11025: |
211 | fscode = 2; |
212 | break; |
213 | case 32000: |
214 | case 16000: |
215 | case 8000: |
216 | fscode = 3; |
217 | } |
218 | avio_wb16(s, fscode); /* codec additional info, for AC-3, seems |
219 | to be a frequency code */ |
220 | /* special hack to compensate rounding errors... */ |
221 | if (coded_frame_size == 557) |
222 | coded_frame_size--; |
223 | avio_wb32(s, coded_frame_size); /* frame length */ |
224 | avio_wb32(s, 0x51540); /* unknown */ |
225 | avio_wb32(s, stream->par->bit_rate / 8 * 60); /* bytes per minute */ |
226 | avio_wb32(s, stream->par->bit_rate / 8 * 60); /* bytes per minute */ |
227 | avio_wb16(s, 0x01); |
228 | /* frame length : seems to be very important */ |
229 | avio_wb16(s, coded_frame_size); |
230 | avio_wb32(s, 0); /* unknown */ |
231 | avio_wb16(s, stream->par->sample_rate); /* sample rate */ |
232 | avio_wb32(s, 0x10); /* unknown */ |
233 | avio_wb16(s, stream->par->channels); |
234 | put_str8(s, "Int0"); /* codec name */ |
235 | if (stream->par->codec_tag) { |
236 | avio_w8(s, 4); /* tag length */ |
237 | avio_wl32(s, stream->par->codec_tag); |
238 | } else { |
239 | av_log(ctx, AV_LOG_ERROR, "Invalid codec tag\n"); |
240 | return -1; |
241 | } |
242 | avio_wb16(s, 0); /* title length */ |
243 | avio_wb16(s, 0); /* author length */ |
244 | avio_wb16(s, 0); /* copyright length */ |
245 | avio_w8(s, 0); /* end of header */ |
246 | } else { |
247 | /* video codec info */ |
248 | avio_wb32(s,34); /* size */ |
249 | ffio_wfourcc(s, "VIDO"); |
250 | if(stream->par->codec_id == AV_CODEC_ID_RV10) |
251 | ffio_wfourcc(s,"RV10"); |
252 | else |
253 | ffio_wfourcc(s,"RV20"); |
254 | avio_wb16(s, stream->par->width); |
255 | avio_wb16(s, stream->par->height); |
256 | |
257 | if (stream->frame_rate.num / stream->frame_rate.den > 65535) { |
258 | av_log(s, AV_LOG_ERROR, "Frame rate %d is too high\n", stream->frame_rate.num / stream->frame_rate.den); |
259 | return AVERROR(EINVAL); |
260 | } |
261 | |
262 | avio_wb16(s, stream->frame_rate.num / stream->frame_rate.den); /* frames per seconds ? */ |
263 | avio_wb32(s,0); /* unknown meaning */ |
264 | avio_wb16(s, stream->frame_rate.num / stream->frame_rate.den); /* unknown meaning */ |
265 | avio_wb32(s,0); /* unknown meaning */ |
266 | avio_wb16(s, 8); /* unknown meaning */ |
267 | /* Seems to be the codec version: only use basic H.263. The next |
268 | versions seems to add a differential DC coding as in |
269 | MPEG... nothing new under the sun. */ |
270 | if(stream->par->codec_id == AV_CODEC_ID_RV10) |
271 | avio_wb32(s,0x10000000); |
272 | else |
273 | avio_wb32(s,0x20103001); |
274 | //avio_wb32(s,0x10003000); |
275 | } |
276 | } |
277 | |
278 | /* patch data offset field */ |
279 | data_pos = s->buf_ptr - start_ptr; |
280 | rm->data_pos = data_pos; |
281 | data_offset_ptr[0] = data_pos >> 24; |
282 | data_offset_ptr[1] = data_pos >> 16; |
283 | data_offset_ptr[2] = data_pos >> 8; |
284 | data_offset_ptr[3] = data_pos; |
285 | |
286 | /* data stream */ |
287 | ffio_wfourcc(s, "DATA"); |
288 | avio_wb32(s,data_size + 10 + 8); |
289 | avio_wb16(s,0); |
290 | |
291 | avio_wb32(s, nb_packets); /* number of packets */ |
292 | avio_wb32(s,0); /* next data header */ |
293 | return 0; |
294 | } |
295 | |
296 | static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream, |
297 | int length, int key_frame) |
298 | { |
299 | int timestamp; |
300 | AVIOContext *s = ctx->pb; |
301 | |
302 | stream->nb_packets++; |
303 | stream->packet_total_size += length; |
304 | if (length > stream->packet_max_size) |
305 | stream->packet_max_size = length; |
306 | |
307 | avio_wb16(s,0); /* version */ |
308 | avio_wb16(s,length + 12); |
309 | avio_wb16(s, stream->num); /* stream number */ |
310 | timestamp = av_rescale_q_rnd(stream->nb_frames, (AVRational){1000, 1}, stream->frame_rate, AV_ROUND_ZERO); |
311 | avio_wb32(s, timestamp); /* timestamp */ |
312 | avio_w8(s, 0); /* reserved */ |
313 | avio_w8(s, key_frame ? 2 : 0); /* flags */ |
314 | } |
315 | |
316 | static int rm_write_header(AVFormatContext *s) |
317 | { |
318 | RMMuxContext *rm = s->priv_data; |
319 | StreamInfo *stream; |
320 | int n; |
321 | AVCodecParameters *par; |
322 | |
323 | if (s->nb_streams > 2) { |
324 | av_log(s, AV_LOG_ERROR, "At most 2 streams are currently supported for muxing in RM\n"); |
325 | return AVERROR_PATCHWELCOME; |
326 | } |
327 | |
328 | for(n=0;n<s->nb_streams;n++) { |
329 | AVStream *st = s->streams[n]; |
330 | int frame_size; |
331 | |
332 | s->streams[n]->id = n; |
333 | par = s->streams[n]->codecpar; |
334 | stream = &rm->streams[n]; |
335 | memset(stream, 0, sizeof(StreamInfo)); |
336 | stream->num = n; |
337 | stream->bit_rate = par->bit_rate; |
338 | stream->par = par; |
339 | |
340 | switch (par->codec_type) { |
341 | case AVMEDIA_TYPE_AUDIO: |
342 | rm->audio_stream = stream; |
343 | frame_size = av_get_audio_frame_duration2(par, 0); |
344 | stream->frame_rate = (AVRational){par->sample_rate, frame_size}; |
345 | /* XXX: dummy values */ |
346 | stream->packet_max_size = 1024; |
347 | stream->nb_packets = 0; |
348 | stream->total_frames = stream->nb_packets; |
349 | break; |
350 | case AVMEDIA_TYPE_VIDEO: |
351 | rm->video_stream = stream; |
352 | // TODO: should be avg_frame_rate |
353 | stream->frame_rate = av_inv_q(st->time_base); |
354 | /* XXX: dummy values */ |
355 | stream->packet_max_size = 4096; |
356 | stream->nb_packets = 0; |
357 | stream->total_frames = stream->nb_packets; |
358 | break; |
359 | default: |
360 | return -1; |
361 | } |
362 | } |
363 | |
364 | if (rv10_write_header(s, 0, 0)) |
365 | return AVERROR_INVALIDDATA; |
366 | avio_flush(s->pb); |
367 | return 0; |
368 | } |
369 | |
370 | static int rm_write_audio(AVFormatContext *s, const uint8_t *buf, int size, int flags) |
371 | { |
372 | RMMuxContext *rm = s->priv_data; |
373 | AVIOContext *pb = s->pb; |
374 | StreamInfo *stream = rm->audio_stream; |
375 | int i; |
376 | |
377 | write_packet_header(s, stream, size, !!(flags & AV_PKT_FLAG_KEY)); |
378 | |
379 | if (stream->par->codec_id == AV_CODEC_ID_AC3) { |
380 | /* for AC-3, the words seem to be reversed */ |
381 | for (i = 0; i < size; i += 2) { |
382 | avio_w8(pb, buf[i + 1]); |
383 | avio_w8(pb, buf[i]); |
384 | } |
385 | } else { |
386 | avio_write(pb, buf, size); |
387 | } |
388 | stream->nb_frames++; |
389 | return 0; |
390 | } |
391 | |
392 | static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int flags) |
393 | { |
394 | RMMuxContext *rm = s->priv_data; |
395 | AVIOContext *pb = s->pb; |
396 | StreamInfo *stream = rm->video_stream; |
397 | int key_frame = !!(flags & AV_PKT_FLAG_KEY); |
398 | |
399 | /* XXX: this is incorrect: should be a parameter */ |
400 | |
401 | /* Well, I spent some time finding the meaning of these bits. I am |
402 | not sure I understood everything, but it works !! */ |
403 | if (size > MAX_PACKET_SIZE) { |
404 | av_log(s, AV_LOG_ERROR, "Muxing packets larger than 64 kB (%d) is not supported\n", size); |
405 | return AVERROR_PATCHWELCOME; |
406 | } |
407 | write_packet_header(s, stream, size + 7 + (size >= 0x4000)*4, key_frame); |
408 | /* bit 7: '1' if final packet of a frame converted in several packets */ |
409 | avio_w8(pb, 0x81); |
410 | /* bit 7: '1' if I-frame. bits 6..0 : sequence number in current |
411 | frame starting from 1 */ |
412 | if (key_frame) { |
413 | avio_w8(pb, 0x81); |
414 | } else { |
415 | avio_w8(pb, 0x01); |
416 | } |
417 | if(size >= 0x4000){ |
418 | avio_wb32(pb, size); /* total frame size */ |
419 | avio_wb32(pb, size); /* offset from the start or the end */ |
420 | }else{ |
421 | avio_wb16(pb, 0x4000 | size); /* total frame size */ |
422 | avio_wb16(pb, 0x4000 | size); /* offset from the start or the end */ |
423 | } |
424 | avio_w8(pb, stream->nb_frames & 0xff); |
425 | |
426 | avio_write(pb, buf, size); |
427 | |
428 | stream->nb_frames++; |
429 | return 0; |
430 | } |
431 | |
432 | static int rm_write_packet(AVFormatContext *s, AVPacket *pkt) |
433 | { |
434 | if (s->streams[pkt->stream_index]->codecpar->codec_type == |
435 | AVMEDIA_TYPE_AUDIO) |
436 | return rm_write_audio(s, pkt->data, pkt->size, pkt->flags); |
437 | else |
438 | return rm_write_video(s, pkt->data, pkt->size, pkt->flags); |
439 | } |
440 | |
441 | static int rm_write_trailer(AVFormatContext *s) |
442 | { |
443 | RMMuxContext *rm = s->priv_data; |
444 | int data_size, index_pos, i; |
445 | AVIOContext *pb = s->pb; |
446 | |
447 | if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { |
448 | /* end of file: finish to write header */ |
449 | index_pos = avio_tell(pb); |
450 | data_size = index_pos - rm->data_pos; |
451 | |
452 | /* FIXME: write index */ |
453 | |
454 | /* undocumented end header */ |
455 | avio_wb32(pb, 0); |
456 | avio_wb32(pb, 0); |
457 | |
458 | avio_seek(pb, 0, SEEK_SET); |
459 | for(i=0;i<s->nb_streams;i++) |
460 | rm->streams[i].total_frames = rm->streams[i].nb_frames; |
461 | rv10_write_header(s, data_size, 0); |
462 | } else { |
463 | /* undocumented end header */ |
464 | avio_wb32(pb, 0); |
465 | avio_wb32(pb, 0); |
466 | } |
467 | |
468 | return 0; |
469 | } |
470 | |
471 | |
472 | AVOutputFormat ff_rm_muxer = { |
473 | .name = "rm", |
474 | .long_name = NULL_IF_CONFIG_SMALL("RealMedia"), |
475 | .mime_type = "application/vnd.rn-realmedia", |
476 | .extensions = "rm,ra", |
477 | .priv_data_size = sizeof(RMMuxContext), |
478 | .audio_codec = AV_CODEC_ID_AC3, |
479 | .video_codec = AV_CODEC_ID_RV10, |
480 | .write_header = rm_write_header, |
481 | .write_packet = rm_write_packet, |
482 | .write_trailer = rm_write_trailer, |
483 | .codec_tag = (const AVCodecTag* const []){ ff_rm_codec_tags, 0 }, |
484 | }; |
485 |