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