test
[libav.git] / rmenc.c
1 /*
2 * RV 1.0 compatible encoder.
3 * Copyright (c) 2000 Gerard Lantau.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <netinet/in.h>
22 #include <string.h>
23 #include "mpegenc.h"
24 #include "mpegvideo.h"
25
26 /* in ms */
27 #define BUFFER_DURATION 0
28
29 typedef struct {
30 int nb_packets;
31 int packet_total_size;
32 int packet_max_size;
33 /* codec related output */
34 int bit_rate;
35 float frame_rate;
36 int nb_frames; /* current frame number */
37 int total_frames; /* total number of frames */
38 int num;
39 AVEncodeContext *enc;
40 } StreamInfo;
41
42 typedef struct {
43 StreamInfo streams[2];
44 StreamInfo *audio_stream, *video_stream;
45 int nb_streams;
46 int data_pos; /* position of the data after the header */
47 } RMContext;
48
49 static void put_long(PutByteContext *s, unsigned int val)
50 {
51 put_byte(s, val >> 24);
52 put_byte(s, val >> 16);
53 put_byte(s, val >> 8);
54 put_byte(s, val);
55 }
56
57 static void put_short(PutByteContext *s, unsigned int val)
58 {
59 put_byte(s, val >> 8);
60 put_byte(s, val);
61 }
62
63 static void put_str(PutByteContext *s, const char *tag)
64 {
65 put_short(s,strlen(tag));
66 while (*tag) {
67 put_byte(s, *tag++);
68 }
69 }
70
71 static void put_str8(PutByteContext *s, const char *tag)
72 {
73 put_byte(s, strlen(tag));
74 while (*tag) {
75 put_byte(s, *tag++);
76 }
77 }
78
79 int find_tag(const char *tag, char *buf, int buf_size, const char *str)
80 {
81 int len = strlen(tag);
82 char *q;
83
84 buf[0] = '\0';
85 while (*str) {
86 if (*str == '+' && !strncmp(str + 1, tag, len) && str[len+1] == '=') {
87 str += len + 2;
88 q = buf;
89 while (*str && *str != '+' && (q - buf) < (buf_size - 1)) {
90 *q++ = *str++;
91 }
92 /* remove trailing spaces */
93 while (q > buf && q[-1] == ' ') q--;
94 *q = '\0';
95 return 1;
96 }
97 str++;
98 }
99 return 0;
100 }
101
102 static void rv10_write_header(AVFormatContext *ctx,
103 int data_size, int index_pos)
104 {
105 RMContext *rm = ctx->priv_data;
106 PutByteContext *s = &ctx->pb;
107 StreamInfo *stream;
108 unsigned char *data_offset_ptr, *start_ptr;
109 char title[1024], author[1024], copyright[1024], comment[1024];
110 const char *desc, *mimetype;
111 int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i;
112 int bit_rate, v, duration, flags, data_pos;
113
114 start_ptr = s->buf_ptr;
115
116 put_tag(s, ".RMF");
117 put_long(s,18); /* header size */
118 put_short(s,0);
119 put_long(s,0);
120 put_long(s,4 + rm->nb_streams); /* num headers */
121
122 put_tag(s,"PROP");
123 put_long(s, 50);
124 put_short(s, 0);
125 packet_max_size = 0;
126 packet_total_size = 0;
127 nb_packets = 0;
128 bit_rate = 0;
129 duration = 0;
130 for(i=0;i<rm->nb_streams;i++) {
131 StreamInfo *stream = &rm->streams[i];
132 bit_rate += stream->bit_rate;
133 if (stream->packet_max_size > packet_max_size)
134 packet_max_size = stream->packet_max_size;
135 nb_packets += stream->nb_packets;
136 packet_total_size += stream->packet_total_size;
137 /* select maximum duration */
138 v = (int) (1000.0 * (float)stream->total_frames / stream->frame_rate);
139 if (v > duration)
140 duration = v;
141 }
142 put_long(s, bit_rate); /* max bit rate */
143 put_long(s, bit_rate); /* avg bit rate */
144 put_long(s, packet_max_size); /* max packet size */
145 if (nb_packets > 0)
146 packet_avg_size = packet_total_size / nb_packets;
147 else
148 packet_avg_size = 0;
149 put_long(s, packet_avg_size); /* avg packet size */
150 put_long(s, nb_packets); /* num packets */
151 put_long(s, duration); /* duration */
152 put_long(s, BUFFER_DURATION); /* preroll */
153 put_long(s, index_pos); /* index offset */
154 /* computation of data the data offset */
155 data_offset_ptr = s->buf_ptr;
156 put_long(s, 0); /* data offset : will be patched after */
157 put_short(s, rm->nb_streams); /* num streams */
158 flags = 1 | 2; /* save allowed & perfect play */
159 if (ctx->is_streamed)
160 flags |= 4; /* live broadcast */
161 put_short(s, flags);
162
163 /* comments */
164 find_tag("title", title, sizeof(title), comment_string);
165 find_tag("author", author, sizeof(author), comment_string);
166 find_tag("copyright", copyright, sizeof(copyright), comment_string);
167 find_tag("comment", comment, sizeof(comment), comment_string);
168
169 put_tag(s,"CONT");
170 size = strlen(title) + strlen(author) + strlen(copyright) + strlen(comment) +
171 4 * 2 + 10;
172 put_long(s,size);
173 put_short(s,0);
174 put_str(s, title);
175 put_str(s, author);
176 put_str(s, copyright);
177 put_str(s, comment);
178
179 for(i=0;i<rm->nb_streams;i++) {
180 int codec_data_size;
181
182 stream = &rm->streams[i];
183
184 if (stream->enc->codec->type == CODEC_TYPE_AUDIO) {
185 desc = "The Audio Stream";
186 mimetype = "audio/x-pn-realaudio";
187 codec_data_size = 73;
188 } else {
189 desc = "The Video Stream";
190 mimetype = "video/x-pn-realvideo";
191 codec_data_size = 34;
192 }
193
194 put_tag(s,"MDPR");
195 size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size;
196 put_long(s, size);
197 put_short(s, 0);
198
199 put_short(s, i); /* stream number */
200 put_long(s, stream->bit_rate); /* max bit rate */
201 put_long(s, stream->bit_rate); /* avg bit rate */
202 put_long(s, stream->packet_max_size); /* max packet size */
203 if (stream->nb_packets > 0)
204 packet_avg_size = stream->packet_total_size /
205 stream->nb_packets;
206 else
207 packet_avg_size = 0;
208 put_long(s, packet_avg_size); /* avg packet size */
209 put_long(s, 0); /* start time */
210 put_long(s, BUFFER_DURATION); /* preroll */
211 /* duration */
212 put_long(s, (int)(stream->total_frames * 1000 / stream->frame_rate));
213 put_str8(s, desc);
214 put_str8(s, mimetype);
215 put_long(s, codec_data_size);
216
217 if (stream->enc->codec->type == CODEC_TYPE_AUDIO) {
218 int coded_frame_size, fscode, sample_rate;
219 sample_rate = stream->enc->rate;
220 coded_frame_size = (stream->enc->bit_rate *
221 stream->enc->frame_size) / (8 * sample_rate);
222 /* audio codec info */
223 put_tag(s, ".ra");
224 put_byte(s, 0xfd);
225 put_long(s, 0x00040000); /* version */
226 put_tag(s, ".ra4");
227 put_long(s, 0x01b53530); /* stream length */
228 put_short(s, 4); /* unknown */
229 put_long(s, 0x39); /* header size */
230
231 switch(sample_rate) {
232 case 48000:
233 case 24000:
234 case 12000:
235 fscode = 1;
236 break;
237 default:
238 case 44100:
239 case 22050:
240 case 11025:
241 fscode = 2;
242 break;
243 case 32000:
244 case 16000:
245 case 8000:
246 fscode = 3;
247 }
248 put_short(s, fscode); /* codec additional info, for AC3, seems
249 to be a frequency code */
250 /* special hack to compensate rounding errors... */
251 if (coded_frame_size == 557)
252 coded_frame_size--;
253 put_long(s, coded_frame_size); /* frame length */
254 put_long(s, 0x51540); /* unknown */
255 put_long(s, 0x249f0); /* unknown */
256 put_long(s, 0x249f0); /* unknown */
257 put_short(s, 0x01);
258 /* frame length : seems to be very important */
259 put_short(s, coded_frame_size);
260 put_long(s, 0); /* unknown */
261 put_short(s, stream->enc->rate); /* sample rate */
262 put_long(s, 0x10); /* unknown */
263 put_short(s, stream->enc->channels);
264 put_str8(s, "Int0"); /* codec name */
265 put_str8(s, "dnet"); /* codec name */
266 put_short(s, 0); /* title length */
267 put_short(s, 0); /* author length */
268 put_short(s, 0); /* copyright length */
269 put_byte(s, 0); /* end of header */
270 } else {
271 /* video codec info */
272 put_long(s,34); /* size */
273 put_tag(s,"VIDORV10");
274 put_short(s, stream->enc->width);
275 put_short(s, stream->enc->height);
276 put_short(s, 24); /* frames per seconds ? */
277 put_long(s,0); /* unknown meaning */
278 put_short(s, 12); /* unknown meaning */
279 put_long(s,0); /* unknown meaning */
280 put_short(s, 8); /* unknown meaning */
281 /* Seems to be the codec version: only use basic H263. The next
282 versions seems to add a diffential DC coding as in
283 MPEG... nothing new under the sun */
284 put_long(s,0x10000000);
285 //put_long(s,0x10003000);
286 }
287 }
288
289 /* patch data offset field */
290 data_pos = s->buf_ptr - start_ptr;
291 rm->data_pos = data_pos;
292 data_offset_ptr[0] = data_pos >> 24;
293 data_offset_ptr[1] = data_pos >> 16;
294 data_offset_ptr[2] = data_pos >> 8;
295 data_offset_ptr[3] = data_pos;
296
297 /* data stream */
298 put_tag(s,"DATA");
299 put_long(s,data_size + 10 + 8);
300 put_short(s,0);
301
302 put_long(s, nb_packets); /* number of packets */
303 put_long(s,0); /* next data header */
304 }
305
306 static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream,
307 int length, int key_frame)
308 {
309 int timestamp;
310 PutByteContext *s = &ctx->pb;
311
312 stream->nb_packets++;
313 stream->packet_total_size += length;
314 if (length > stream->packet_max_size)
315 stream->packet_max_size = length;
316
317 put_short(s,0); /* version */
318 put_short(s,length + 12);
319 put_short(s, stream->num); /* stream number */
320 timestamp = (1000 * (float)stream->nb_frames) / stream->frame_rate;
321 put_long(s, timestamp); /* timestamp */
322 put_byte(s, 0); /* reserved */
323 put_byte(s, key_frame ? 2 : 0); /* flags */
324 }
325
326 static int rm_write_header(AVFormatContext *s)
327 {
328 StreamInfo *stream;
329 RMContext *rm;
330 int n;
331
332 rm = malloc(sizeof(RMContext));
333 if (!rm)
334 return -1;
335 memset(rm, 0, sizeof(RMContext));
336 s->priv_data = rm;
337 n = 0;
338 if (s->audio_enc) {
339 stream = &rm->streams[n];
340 memset(stream, 0, sizeof(StreamInfo));
341 stream->num = n;
342 rm->audio_stream = stream;
343 stream->bit_rate = s->audio_enc->bit_rate;
344 stream->frame_rate = (float)s->audio_enc->rate / (float)s->audio_enc->frame_size;
345 stream->enc = s->audio_enc;
346 /* XXX: dummy values */
347 stream->packet_max_size = 1024;
348 stream->nb_packets = 1000;
349 stream->total_frames = stream->nb_packets;
350 n++;
351 }
352 if (s->video_enc) {
353 stream = &rm->streams[n];
354 memset(stream, 0, sizeof(StreamInfo));
355 stream->num = n;
356 rm->video_stream = stream;
357 stream->bit_rate = s->video_enc->bit_rate;
358 stream->frame_rate = s->video_enc->rate;
359 stream->enc = s->video_enc;
360 /* XXX: dummy values */
361 stream->packet_max_size = 4096;
362 stream->nb_packets = 1000;
363 stream->total_frames = stream->nb_packets;
364 n++;
365 }
366 rm->nb_streams = n;
367
368 rv10_write_header(s, 0, 0);
369 put_flush_packet(&s->pb);
370 return 0;
371 }
372
373 static int rm_write_audio(AVFormatContext *s, UINT8 *buf, int size)
374 {
375 UINT8 buf1[size];
376 RMContext *rm = s->priv_data;
377 PutByteContext *pb = &s->pb;
378 StreamInfo *stream = rm->audio_stream;
379 int i;
380
381 write_packet_header(s, stream, size, stream->enc->key_frame);
382
383 /* for AC3, the words seems to be reversed */
384 for(i=0;i<size;i+=2) {
385 buf1[i] = buf[i+1];
386 buf1[i+1] = buf[i];
387 }
388 put_buffer(pb, buf1, size);
389 put_flush_packet(pb);
390 stream->nb_frames++;
391 return 0;
392 }
393
394 static int rm_write_video(AVFormatContext *s, UINT8 *buf, int size)
395 {
396 RMContext *rm = s->priv_data;
397 PutByteContext *pb = &s->pb;
398 StreamInfo *stream = rm->video_stream;
399 int key_frame = stream->enc->key_frame;
400
401 /* XXX: this is incorrect: should be a parameter */
402
403 /* Well, I spent some time finding the meaning of these bits. I am
404 not sure I understood everything, but it works !! */
405 #if 1
406 write_packet_header(s, stream, size + 7, key_frame);
407 /* bit 7: '1' if final packet of a frame converted in several packets */
408 put_byte(pb, 0x81);
409 /* bit 7: '1' if I frame. bits 6..0 : sequence number in current
410 frame starting from 1 */
411 if (key_frame) {
412 put_byte(pb, 0x81);
413 } else {
414 put_byte(pb, 0x01);
415 }
416 put_short(pb, 0x4000 | (size)); /* total frame size */
417 put_short(pb, 0x4000 | (size)); /* offset from the start or the end */
418 #else
419 /* seems to be used for prefetch/error correction. Help me ! */
420 write_packet_header(s, size + 6);
421 put_byte(pb, 0xc0);
422 put_short(pb, 0x4000 | size); /* total frame size */
423 put_short(pb, 0x4000 + packet_number * 126);
424 #endif
425 put_byte(pb, stream->nb_frames & 0xff);
426
427 put_buffer(pb, buf, size);
428 put_flush_packet(pb);
429
430 stream->nb_frames++;
431 return 0;
432 }
433
434 static int rm_write_trailer(AVFormatContext *s)
435 {
436 RMContext *rm = s->priv_data;
437 int data_size, index_pos, i;
438 PutByteContext *pb = &s->pb;
439
440 if (!s->is_streamed) {
441 /* end of file: finish to write header */
442 index_pos = put_seek(pb, 0, SEEK_CUR);
443 data_size = index_pos - rm->data_pos;
444
445 /* index */
446 put_tag(pb, "INDX");
447 put_long(pb, 10 + 10 * rm->nb_streams);
448 put_short(pb, 0);
449
450 for(i=0;i<rm->nb_streams;i++) {
451 put_long(pb, 0); /* zero indices */
452 put_short(pb, i); /* stream number */
453 put_long(pb, 0); /* next index */
454 }
455 /* undocumented end header */
456 put_long(pb, 0);
457 put_long(pb, 0);
458
459 put_seek(pb, 0, SEEK_SET);
460 for(i=0;i<rm->nb_streams;i++)
461 rm->streams[i].total_frames = rm->streams[i].nb_frames;
462 rv10_write_header(s, data_size, index_pos);
463 } else {
464 /* undocumented end header */
465 put_long(pb, 0);
466 put_long(pb, 0);
467 }
468 put_flush_packet(pb);
469
470 free(rm);
471 return 0;
472 }
473
474 AVFormat rm_format = {
475 "rm",
476 "rm format",
477 "audio/x-pn-realaudio",
478 "rm,ra",
479 CODEC_ID_AC3,
480 CODEC_ID_RV10,
481 rm_write_header,
482 rm_write_audio,
483 rm_write_video,
484 rm_write_trailer,
485 };
486
487 AVFormat ra_format = {
488 "ra",
489 "ra format",
490 "audio/x-pn-realaudio",
491 "ra",
492 CODEC_ID_AC3,
493 CODEC_ID_NONE,
494 rm_write_header,
495 rm_write_audio,
496 NULL,
497 rm_write_trailer,
498 };