2 * Copyright (C) 2002-2003 the xine project
4 * This file is part of xine, a free video player.
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
22 * functions for real media file format
23 * adopted from joschkas real tools
27 #include "real_rmff.h"
29 #include <vlc_messages.h>
31 #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])
32 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \
33 (((uint8_t*)(x))[1] << 16) | \
34 (((uint8_t*)(x))[2] << 8) | \
38 * writes header data to a buffer
41 static int rmff_dump_fileheader(rmff_fileheader_t
*fileheader
, uint8_t *buffer
, int bufsize
) {
42 if (!fileheader
) return 0;
43 if (bufsize
< RMFF_FILEHEADER_SIZE
)
46 fileheader
->object_id
=BE_32(&fileheader
->object_id
);
47 fileheader
->size
=BE_32(&fileheader
->size
);
48 fileheader
->object_version
=BE_16(&fileheader
->object_version
);
49 fileheader
->file_version
=BE_32(&fileheader
->file_version
);
50 fileheader
->num_headers
=BE_32(&fileheader
->num_headers
);
52 memcpy(buffer
, fileheader
, 8);
53 memcpy(&buffer
[8], &fileheader
->object_version
, 2);
54 memcpy(&buffer
[10], &fileheader
->file_version
, 8);
56 fileheader
->size
=BE_32(&fileheader
->size
);
57 fileheader
->object_version
=BE_16(&fileheader
->object_version
);
58 fileheader
->file_version
=BE_32(&fileheader
->file_version
);
59 fileheader
->num_headers
=BE_32(&fileheader
->num_headers
);
60 fileheader
->object_id
=BE_32(&fileheader
->object_id
);
62 return RMFF_FILEHEADER_SIZE
;
65 static int rmff_dump_prop(rmff_prop_t
*prop
, uint8_t *buffer
, int bufsize
) {
69 if (bufsize
< RMFF_PROPHEADER_SIZE
)
72 prop
->object_id
=BE_32(&prop
->object_id
);
73 prop
->size
=BE_32(&prop
->size
);
74 prop
->object_version
=BE_16(&prop
->object_version
);
75 prop
->max_bit_rate
=BE_32(&prop
->max_bit_rate
);
76 prop
->avg_bit_rate
=BE_32(&prop
->avg_bit_rate
);
77 prop
->max_packet_size
=BE_32(&prop
->max_packet_size
);
78 prop
->avg_packet_size
=BE_32(&prop
->avg_packet_size
);
79 prop
->num_packets
=BE_32(&prop
->num_packets
);
80 prop
->duration
=BE_32(&prop
->duration
);
81 prop
->preroll
=BE_32(&prop
->preroll
);
82 prop
->index_offset
=BE_32(&prop
->index_offset
);
83 prop
->data_offset
=BE_32(&prop
->data_offset
);
84 prop
->num_streams
=BE_16(&prop
->num_streams
);
85 prop
->flags
=BE_16(&prop
->flags
);
87 memcpy(buffer
, prop
, 8);
88 memcpy(&buffer
[8], &prop
->object_version
, 2);
89 memcpy(&buffer
[10], &prop
->max_bit_rate
, 36);
90 memcpy(&buffer
[46], &prop
->num_streams
, 2);
91 memcpy(&buffer
[48], &prop
->flags
, 2);
93 prop
->size
=BE_32(&prop
->size
);
94 prop
->object_version
=BE_16(&prop
->object_version
);
95 prop
->max_bit_rate
=BE_32(&prop
->max_bit_rate
);
96 prop
->avg_bit_rate
=BE_32(&prop
->avg_bit_rate
);
97 prop
->max_packet_size
=BE_32(&prop
->max_packet_size
);
98 prop
->avg_packet_size
=BE_32(&prop
->avg_packet_size
);
99 prop
->num_packets
=BE_32(&prop
->num_packets
);
100 prop
->duration
=BE_32(&prop
->duration
);
101 prop
->preroll
=BE_32(&prop
->preroll
);
102 prop
->index_offset
=BE_32(&prop
->index_offset
);
103 prop
->data_offset
=BE_32(&prop
->data_offset
);
104 prop
->num_streams
=BE_16(&prop
->num_streams
);
105 prop
->flags
=BE_16(&prop
->flags
);
106 prop
->object_id
=BE_32(&prop
->object_id
);
108 return RMFF_PROPHEADER_SIZE
;
111 static int rmff_dump_mdpr(rmff_mdpr_t
*mdpr
, uint8_t *buffer
, unsigned int bufsize
) {
116 if (bufsize
< RMFF_MDPRHEADER_SIZE
+ mdpr
->type_specific_len
+
117 mdpr
->stream_name_size
+ mdpr
->mime_type_size
)
120 mdpr
->object_id
=BE_32(&mdpr
->object_id
);
121 mdpr
->size
=BE_32(&mdpr
->size
);
122 mdpr
->object_version
=BE_16(&mdpr
->object_version
);
123 mdpr
->stream_number
=BE_16(&mdpr
->stream_number
);
124 mdpr
->max_bit_rate
=BE_32(&mdpr
->max_bit_rate
);
125 mdpr
->avg_bit_rate
=BE_32(&mdpr
->avg_bit_rate
);
126 mdpr
->max_packet_size
=BE_32(&mdpr
->max_packet_size
);
127 mdpr
->avg_packet_size
=BE_32(&mdpr
->avg_packet_size
);
128 mdpr
->start_time
=BE_32(&mdpr
->start_time
);
129 mdpr
->preroll
=BE_32(&mdpr
->preroll
);
130 mdpr
->duration
=BE_32(&mdpr
->duration
);
132 memcpy(buffer
, mdpr
, 8);
133 memcpy(&buffer
[8], &mdpr
->object_version
, 2);
134 memcpy(&buffer
[10], &mdpr
->stream_number
, 2);
135 memcpy(&buffer
[12], &mdpr
->max_bit_rate
, 28);
136 memcpy(&buffer
[40], &mdpr
->stream_name_size
, 1);
137 s1
=mdpr
->stream_name_size
;
138 memcpy(&buffer
[41], mdpr
->stream_name
, s1
);
140 memcpy(&buffer
[41+s1
], &mdpr
->mime_type_size
, 1);
141 s2
=mdpr
->mime_type_size
;
142 memcpy(&buffer
[42+s1
], mdpr
->mime_type
, s2
);
144 mdpr
->type_specific_len
=BE_32(&mdpr
->type_specific_len
);
145 memcpy(&buffer
[42+s1
+s2
], &mdpr
->type_specific_len
, 4);
146 mdpr
->type_specific_len
=BE_32(&mdpr
->type_specific_len
);
147 s3
=mdpr
->type_specific_len
;
148 memcpy(&buffer
[46+s1
+s2
], mdpr
->type_specific_data
, s3
);
150 mdpr
->size
=BE_32(&mdpr
->size
);
151 mdpr
->stream_number
=BE_16(&mdpr
->stream_number
);
152 mdpr
->max_bit_rate
=BE_32(&mdpr
->max_bit_rate
);
153 mdpr
->avg_bit_rate
=BE_32(&mdpr
->avg_bit_rate
);
154 mdpr
->max_packet_size
=BE_32(&mdpr
->max_packet_size
);
155 mdpr
->avg_packet_size
=BE_32(&mdpr
->avg_packet_size
);
156 mdpr
->start_time
=BE_32(&mdpr
->start_time
);
157 mdpr
->preroll
=BE_32(&mdpr
->preroll
);
158 mdpr
->duration
=BE_32(&mdpr
->duration
);
159 mdpr
->object_id
=BE_32(&mdpr
->object_id
);
161 return RMFF_MDPRHEADER_SIZE
+ s1
+ s2
+ s3
;
164 static int rmff_dump_cont(rmff_cont_t
*cont
, uint8_t *buffer
, int bufsize
) {
170 if (bufsize
< RMFF_CONTHEADER_SIZE
+ cont
->title_len
+ cont
->author_len
+ \
171 cont
->copyright_len
+ cont
->comment_len
)
174 cont
->object_id
=BE_32(&cont
->object_id
);
175 cont
->size
=BE_32(&cont
->size
);
176 cont
->object_version
=BE_16(&cont
->object_version
);
178 memcpy(buffer
, cont
, 8);
179 memcpy(&buffer
[8], &cont
->object_version
, 2);
181 cont
->title_len
=BE_16(&cont
->title_len
);
182 memcpy(&buffer
[10], &cont
->title_len
, 2);
183 cont
->title_len
=BE_16(&cont
->title_len
);
184 memcpy(&buffer
[12], cont
->title
, cont
->title_len
);
185 p
=12+cont
->title_len
;
187 cont
->author_len
=BE_16(&cont
->author_len
);
188 memcpy(&buffer
[p
], &cont
->author_len
, 2);
189 cont
->author_len
=BE_16(&cont
->author_len
);
190 memcpy(&buffer
[p
+2], cont
->author
, cont
->author_len
);
191 p
+=2+cont
->author_len
;
193 cont
->copyright_len
=BE_16(&cont
->copyright_len
);
194 memcpy(&buffer
[p
], &cont
->copyright_len
, 2);
195 cont
->copyright_len
=BE_16(&cont
->copyright_len
);
196 memcpy(&buffer
[p
+2], cont
->copyright
, cont
->copyright_len
);
197 p
+=2+cont
->copyright_len
;
199 cont
->comment_len
=BE_16(&cont
->comment_len
);
200 memcpy(&buffer
[p
], &cont
->comment_len
, 2);
201 cont
->comment_len
=BE_16(&cont
->comment_len
);
202 memcpy(&buffer
[p
+2], cont
->comment
, cont
->comment_len
);
204 cont
->size
=BE_32(&cont
->size
);
205 cont
->object_version
=BE_16(&cont
->object_version
);
206 cont
->object_id
=BE_32(&cont
->object_id
);
208 return RMFF_CONTHEADER_SIZE
+ cont
->title_len
+ cont
->author_len
+ \
209 cont
->copyright_len
+ cont
->comment_len
;
212 static int rmff_dump_dataheader(rmff_data_t
*data
, uint8_t *buffer
, int bufsize
) {
216 if (bufsize
< RMFF_DATAHEADER_SIZE
)
220 data
->object_id
=BE_32(&data
->object_id
);
221 data
->size
=BE_32(&data
->size
);
222 data
->object_version
=BE_16(&data
->object_version
);
223 data
->num_packets
=BE_32(&data
->num_packets
);
224 data
->next_data_header
=BE_32(&data
->next_data_header
);
226 memcpy(buffer
, data
, 8);
227 memcpy(&buffer
[8], &data
->object_version
, 2);
228 memcpy(&buffer
[10], &data
->num_packets
, 8);
230 data
->num_packets
=BE_32(&data
->num_packets
);
231 data
->next_data_header
=BE_32(&data
->next_data_header
);
232 data
->size
=BE_32(&data
->size
);
233 data
->object_version
=BE_16(&data
->object_version
);
234 data
->object_id
=BE_32(&data
->object_id
);
236 return RMFF_DATAHEADER_SIZE
;
239 int rmff_dump_header(rmff_header_t
*h
, void *buf_gen
, int max
) {
240 uint8_t *buffer
= buf_gen
;
243 rmff_mdpr_t
**stream
=h
->streams
;
245 if ((size
=rmff_dump_fileheader(h
->fileheader
, &buffer
[written
], max
)) < 0)
251 if ((size
=rmff_dump_prop(h
->prop
, &buffer
[written
], max
)) < 0)
257 if ((size
=rmff_dump_cont(h
->cont
, &buffer
[written
], max
)) < 0)
265 if ((size
=rmff_dump_mdpr(*stream
, &buffer
[written
], max
)) < 0)
273 if ((size
=rmff_dump_dataheader(h
->data
, &buffer
[written
], max
)) < 0)
281 void rmff_dump_pheader(rmff_pheader_t
*h
, char *data
) {
283 data
[0]=(h
->object_version
>>8) & 0xff;
284 data
[1]=h
->object_version
& 0xff;
285 data
[2]=(h
->length
>>8) & 0xff;
286 data
[3]=h
->length
& 0xff;
287 data
[4]=(h
->stream_number
>>8) & 0xff;
288 data
[5]=h
->stream_number
& 0xff;
289 data
[6]=(h
->timestamp
>>24) & 0xff;
290 data
[7]=(h
->timestamp
>>16) & 0xff;
291 data
[8]=(h
->timestamp
>>8) & 0xff;
292 data
[9]=h
->timestamp
& 0xff;
293 data
[10]=h
->reserved
;
297 rmff_fileheader_t
*rmff_new_fileheader(uint32_t num_headers
) {
299 rmff_fileheader_t
*fileheader
= calloc( 1, sizeof(rmff_fileheader_t
) );
303 fileheader
->object_id
=RMF_TAG
;
305 fileheader
->object_version
=0;
306 fileheader
->file_version
=0;
307 fileheader
->num_headers
=num_headers
;
312 rmff_prop_t
*rmff_new_prop (
313 uint32_t max_bit_rate
,
314 uint32_t avg_bit_rate
,
315 uint32_t max_packet_size
,
316 uint32_t avg_packet_size
,
317 uint32_t num_packets
,
320 uint32_t index_offset
,
321 uint32_t data_offset
,
322 uint16_t num_streams
,
325 rmff_prop_t
*prop
= calloc( 1, sizeof(rmff_prop_t
) );
329 prop
->object_id
=PROP_TAG
;
331 prop
->object_version
=0;
332 prop
->max_bit_rate
=max_bit_rate
;
333 prop
->avg_bit_rate
=avg_bit_rate
;
334 prop
->max_packet_size
=max_packet_size
;
335 prop
->avg_packet_size
=avg_packet_size
;
336 prop
->num_packets
=num_packets
;
337 prop
->duration
=duration
;
338 prop
->preroll
=preroll
;
339 prop
->index_offset
=index_offset
;
340 prop
->data_offset
=data_offset
;
341 prop
->num_streams
=num_streams
;
347 rmff_mdpr_t
*rmff_new_mdpr(
348 uint16_t stream_number
,
349 uint32_t max_bit_rate
,
350 uint32_t avg_bit_rate
,
351 uint32_t max_packet_size
,
352 uint32_t avg_packet_size
,
356 const char *stream_name
,
357 const char *mime_type
,
358 uint32_t type_specific_len
,
359 const char *type_specific_data
) {
361 rmff_mdpr_t
*mdpr
= calloc( 1, sizeof(rmff_mdpr_t
) );
365 mdpr
->object_id
=MDPR_TAG
;
366 mdpr
->object_version
=0;
367 mdpr
->stream_number
=stream_number
;
368 mdpr
->max_bit_rate
=max_bit_rate
;
369 mdpr
->avg_bit_rate
=avg_bit_rate
;
370 mdpr
->max_packet_size
=max_packet_size
;
371 mdpr
->avg_packet_size
=avg_packet_size
;
372 mdpr
->start_time
=start_time
;
373 mdpr
->preroll
=preroll
;
374 mdpr
->duration
=duration
;
375 mdpr
->stream_name_size
=0;
377 mdpr
->stream_name
=strdup(stream_name
);
378 mdpr
->stream_name_size
=strlen(stream_name
);
380 mdpr
->mime_type_size
=0;
382 mdpr
->mime_type
=strdup(mime_type
);
383 mdpr
->mime_type_size
=strlen(mime_type
);
385 mdpr
->type_specific_len
=type_specific_len
;
387 mdpr
->type_specific_data
= malloc(type_specific_len
);
388 if( !mdpr
->type_specific_data
) {
389 free( mdpr
->stream_name
);
393 memcpy(mdpr
->type_specific_data
,type_specific_data
,type_specific_len
);
394 mdpr
->mlti_data
=NULL
;
395 mdpr
->size
=mdpr
->stream_name_size
+mdpr
->mime_type_size
+mdpr
->type_specific_len
+46;
399 rmff_cont_t
*rmff_new_cont(const char *title
, const char *author
, const char *copyright
, const char *comment
) {
401 rmff_cont_t
*cont
= calloc( 1, sizeof(rmff_cont_t
) );
405 cont
->object_id
=CONT_TAG
;
406 cont
->object_version
=0;
409 cont
->copyright
=NULL
;
413 cont
->copyright_len
=0;
417 cont
->title_len
=strlen(title
);
418 cont
->title
=strdup(title
);
422 cont
->author_len
=strlen(author
);
423 cont
->author
=strdup(author
);
426 cont
->copyright_len
=strlen(copyright
);
427 cont
->copyright
=strdup(copyright
);
430 cont
->comment_len
=strlen(comment
);
431 cont
->comment
=strdup(comment
);
433 cont
->size
=cont
->title_len
+cont
->author_len
+cont
->copyright_len
+cont
->comment_len
+18;
437 rmff_data_t
*rmff_new_dataheader(uint32_t num_packets
, uint32_t next_data_header
) {
438 rmff_data_t
*data
= calloc( 1, sizeof(rmff_data_t
) );
442 data
->object_id
=DATA_TAG
;
444 data
->object_version
=0;
445 data
->num_packets
=num_packets
;
446 data
->next_data_header
=next_data_header
;
451 void rmff_print_header(rmff_header_t
*h
) {
452 rmff_mdpr_t
**stream
;
455 printf("rmff_print_header: NULL given\n");
461 printf("file version : %d\n", h
->fileheader
->file_version
);
462 printf("number of headers : %d\n", h
->fileheader
->num_headers
);
466 printf("\nCONTENT:\n");
467 printf("title : %s\n", h
->cont
->title
);
468 printf("author : %s\n", h
->cont
->author
);
469 printf("copyright : %s\n", h
->cont
->copyright
);
470 printf("comment : %s\n", h
->cont
->comment
);
474 printf("\nSTREAM PROPERTIES:\n");
475 printf("bit rate (max/avg) : %i/%i\n", h
->prop
->max_bit_rate
, h
->prop
->avg_bit_rate
);
476 printf("packet size (max/avg) : %i/%i bytes\n", h
->prop
->max_packet_size
, h
->prop
->avg_packet_size
);
477 printf("packets : %i\n", h
->prop
->num_packets
);
478 printf("duration : %i ms\n", h
->prop
->duration
);
479 printf("pre-buffer : %i ms\n", h
->prop
->preroll
);
480 printf("index offset : %i bytes\n", h
->prop
->index_offset
);
481 printf("data offset : %i bytes\n", h
->prop
->data_offset
);
482 printf("media streams : %i\n", h
->prop
->num_streams
);
484 if (h
->prop
->flags
& PN_SAVE_ENABLED
) printf("save_enabled ");
485 if (h
->prop
->flags
& PN_PERFECT_PLAY_ENABLED
) printf("perfect_play_enabled ");
486 if (h
->prop
->flags
& PN_LIVE_BROADCAST
) printf("live_broadcast ");
494 printf("\nSTREAM %i:\n", (*stream
)->stream_number
);
495 printf("stream name [mime type] : %s [%s]\n", (*stream
)->stream_name
, (*stream
)->mime_type
);
496 printf("bit rate (max/avg) : %i/%i\n", (*stream
)->max_bit_rate
, (*stream
)->avg_bit_rate
);
497 printf("packet size (max/avg) : %i/%i bytes\n", (*stream
)->max_packet_size
, (*stream
)->avg_packet_size
);
498 printf("start time : %i\n", (*stream
)->start_time
);
499 printf("pre-buffer : %i ms\n", (*stream
)->preroll
);
500 printf("duration : %i ms\n", (*stream
)->duration
);
501 printf("type specific data:\n");
508 printf("size : %i\n", h
->data
->size
);
509 printf("packets : %i\n", h
->data
->num_packets
);
510 printf("next DATA : 0x%08x\n", h
->data
->next_data_header
);
514 void rmff_fix_header(stream_t
*p_access
, rmff_header_t
*h
) {
516 unsigned int num_headers
=0;
517 unsigned int header_size
=0;
518 rmff_mdpr_t
**streams
;
522 msg_Warn(p_access
, "rmff_fix_header: fatal: no header given.");
526 msg_Warn(p_access
, "rmff_fix_header: warning: no MDPR chunks");
534 header_size
+=(*streams
)->size
;
539 if (h
->prop
->size
!= 50)
541 msg_Dbg(p_access
, "rmff_fix_header: correcting prop.size from %i to %i", h
->prop
->size
, 50);
544 if (h
->prop
->num_streams
!= num_streams
)
546 msg_Dbg(p_access
, "rmff_fix_header: correcting prop.num_streams from %i to %i", h
->prop
->num_streams
, num_streams
);
547 h
->prop
->num_streams
=num_streams
;
552 msg_Warn(p_access
, "rmff_fix_header: warning: no PROP chunk.");
556 header_size
+=h
->cont
->size
;
558 msg_Warn(p_access
, "rmff_fix_header: warning: no CONT chunk.");
561 msg_Warn(p_access
, "rmff_fix_header: no DATA chunk, creating one");
562 h
->data
= calloc( 1, sizeof(rmff_data_t
) );
565 h
->data
->object_id
=DATA_TAG
;
566 h
->data
->object_version
=0;
568 h
->data
->num_packets
=0;
569 h
->data
->next_data_header
=0;
574 if (!h
->fileheader
) {
575 msg_Warn(p_access
, "rmff_fix_header: no fileheader, creating one");
576 h
->fileheader
= calloc( 1, sizeof(rmff_fileheader_t
) );
579 h
->fileheader
->object_id
=RMF_TAG
;
580 h
->fileheader
->size
=18;
581 h
->fileheader
->object_version
=0;
582 h
->fileheader
->file_version
=0;
583 h
->fileheader
->num_headers
=num_headers
+1;
586 header_size
+=h
->fileheader
->size
;
589 if(h
->fileheader
->num_headers
!= num_headers
) {
590 msg_Dbg(p_access
, "rmff_fix_header: setting num_headers from %i to %i", h
->fileheader
->num_headers
, num_headers
);
591 h
->fileheader
->num_headers
=num_headers
;
594 if (h
->prop
->data_offset
!= header_size
) {
595 msg_Dbg(p_access
, "rmff_fix_header: setting prop.data_offset from %i to %i", h
->prop
->data_offset
, header_size
);
596 h
->prop
->data_offset
=header_size
;
599 /* FIXME: I doubt this is right to do this here.
600 * It should belong to the demux. */
601 if (h
->prop
->num_packets
== 0) {
602 int p
=(int)(h
->prop
->avg_bit_rate
/8.0*(h
->prop
->duration
/1000.0)/h
->prop
->avg_packet_size
);
603 msg_Dbg(p_access
, "rmff_fix_header: assuming prop.num_packets=%i", p
);
604 h
->prop
->num_packets
=p
;
606 if (h
->data
->num_packets
== 0) {
607 msg_Dbg(p_access
, "rmff_fix_header: assuming data.num_packets=%i", h
->prop
->num_packets
);
608 h
->data
->num_packets
=h
->prop
->num_packets
;
610 if (h
->data
->size
== 18 || !h
->data
->size
) {
611 msg_Dbg(p_access
, "rmff_fix_header: assuming data.size=%i", h
->prop
->num_packets
*h
->prop
->avg_packet_size
);
612 h
->data
->size
+=h
->prop
->num_packets
*h
->prop
->avg_packet_size
;
617 int rmff_get_header_size(rmff_header_t
*h
) {
619 if (!h
->prop
) return -1;
620 return h
->prop
->data_offset
+18;
623 void rmff_free_header(rmff_header_t
*h
)
627 free( h
->fileheader
);
631 free( h
->cont
->title
);
632 free( h
->cont
->author
);
633 free( h
->cont
->copyright
);
634 free( h
->cont
->comment
);
639 rmff_mdpr_t
**s
=h
->streams
;
642 free((*s
)->stream_name
);
643 free((*s
)->mime_type
);
644 free((*s
)->type_specific_data
);