annotate ffmpeg/libavformat/rmenc.c @ 13:844d341cf643 tip

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