00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avformat.h"
00022 #include "avio_internal.h"
00023 #include "rm.h"
00024 #include "libavutil/dict.h"
00025
00026 typedef struct {
00027 int nb_packets;
00028 int packet_total_size;
00029 int packet_max_size;
00030
00031 int bit_rate;
00032 float frame_rate;
00033 int nb_frames;
00034 int total_frames;
00035 int num;
00036 AVCodecContext *enc;
00037 } StreamInfo;
00038
00039 typedef struct {
00040 StreamInfo streams[2];
00041 StreamInfo *audio_stream, *video_stream;
00042 int data_pos;
00043 } RMMuxContext;
00044
00045
00046 #define BUFFER_DURATION 0
00047
00048
00049 static void put_str(AVIOContext *s, const char *tag)
00050 {
00051 avio_wb16(s,strlen(tag));
00052 while (*tag) {
00053 avio_w8(s, *tag++);
00054 }
00055 }
00056
00057 static void put_str8(AVIOContext *s, const char *tag)
00058 {
00059 avio_w8(s, strlen(tag));
00060 while (*tag) {
00061 avio_w8(s, *tag++);
00062 }
00063 }
00064
00065 static int rv10_write_header(AVFormatContext *ctx,
00066 int data_size, int index_pos)
00067 {
00068 RMMuxContext *rm = ctx->priv_data;
00069 AVIOContext *s = ctx->pb;
00070 StreamInfo *stream;
00071 unsigned char *data_offset_ptr, *start_ptr;
00072 const char *desc, *mimetype;
00073 int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i;
00074 int bit_rate, v, duration, flags, data_pos;
00075 AVDictionaryEntry *tag;
00076
00077 start_ptr = s->buf_ptr;
00078
00079 ffio_wfourcc(s, ".RMF");
00080 avio_wb32(s,18);
00081 avio_wb16(s,0);
00082 avio_wb32(s,0);
00083 avio_wb32(s,4 + ctx->nb_streams);
00084
00085 ffio_wfourcc(s,"PROP");
00086 avio_wb32(s, 50);
00087 avio_wb16(s, 0);
00088 packet_max_size = 0;
00089 packet_total_size = 0;
00090 nb_packets = 0;
00091 bit_rate = 0;
00092 duration = 0;
00093 for(i=0;i<ctx->nb_streams;i++) {
00094 StreamInfo *stream = &rm->streams[i];
00095 bit_rate += stream->bit_rate;
00096 if (stream->packet_max_size > packet_max_size)
00097 packet_max_size = stream->packet_max_size;
00098 nb_packets += stream->nb_packets;
00099 packet_total_size += stream->packet_total_size;
00100
00101 v = (int) (1000.0 * (float)stream->total_frames / stream->frame_rate);
00102 if (v > duration)
00103 duration = v;
00104 }
00105 avio_wb32(s, bit_rate);
00106 avio_wb32(s, bit_rate);
00107 avio_wb32(s, packet_max_size);
00108 if (nb_packets > 0)
00109 packet_avg_size = packet_total_size / nb_packets;
00110 else
00111 packet_avg_size = 0;
00112 avio_wb32(s, packet_avg_size);
00113 avio_wb32(s, nb_packets);
00114 avio_wb32(s, duration);
00115 avio_wb32(s, BUFFER_DURATION);
00116 avio_wb32(s, index_pos);
00117
00118 data_offset_ptr = s->buf_ptr;
00119 avio_wb32(s, 0);
00120 avio_wb16(s, ctx->nb_streams);
00121 flags = 1 | 2;
00122 if (!s->seekable)
00123 flags |= 4;
00124 avio_wb16(s, flags);
00125
00126
00127
00128 ffio_wfourcc(s,"CONT");
00129 size = 4 * 2 + 10;
00130 for(i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) {
00131 tag = av_dict_get(ctx->metadata, ff_rm_metadata[i], NULL, 0);
00132 if(tag) size += strlen(tag->value);
00133 }
00134 avio_wb32(s,size);
00135 avio_wb16(s,0);
00136 for(i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) {
00137 tag = av_dict_get(ctx->metadata, ff_rm_metadata[i], NULL, 0);
00138 put_str(s, tag ? tag->value : "");
00139 }
00140
00141 for(i=0;i<ctx->nb_streams;i++) {
00142 int codec_data_size;
00143
00144 stream = &rm->streams[i];
00145
00146 if (stream->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
00147 desc = "The Audio Stream";
00148 mimetype = "audio/x-pn-realaudio";
00149 codec_data_size = 73;
00150 } else {
00151 desc = "The Video Stream";
00152 mimetype = "video/x-pn-realvideo";
00153 codec_data_size = 34;
00154 }
00155
00156 ffio_wfourcc(s,"MDPR");
00157 size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size;
00158 avio_wb32(s, size);
00159 avio_wb16(s, 0);
00160
00161 avio_wb16(s, i);
00162 avio_wb32(s, stream->bit_rate);
00163 avio_wb32(s, stream->bit_rate);
00164 avio_wb32(s, stream->packet_max_size);
00165 if (stream->nb_packets > 0)
00166 packet_avg_size = stream->packet_total_size /
00167 stream->nb_packets;
00168 else
00169 packet_avg_size = 0;
00170 avio_wb32(s, packet_avg_size);
00171 avio_wb32(s, 0);
00172 avio_wb32(s, BUFFER_DURATION);
00173
00174 if (!s->seekable || !stream->total_frames)
00175 avio_wb32(s, (int)(3600 * 1000));
00176 else
00177 avio_wb32(s, (int)(stream->total_frames * 1000 / stream->frame_rate));
00178 put_str8(s, desc);
00179 put_str8(s, mimetype);
00180 avio_wb32(s, codec_data_size);
00181
00182 if (stream->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
00183 int coded_frame_size, fscode, sample_rate;
00184 sample_rate = stream->enc->sample_rate;
00185 coded_frame_size = (stream->enc->bit_rate *
00186 stream->enc->frame_size) / (8 * sample_rate);
00187
00188 avio_write(s, ".ra", 3);
00189 avio_w8(s, 0xfd);
00190 avio_wb32(s, 0x00040000);
00191 ffio_wfourcc(s, ".ra4");
00192 avio_wb32(s, 0x01b53530);
00193 avio_wb16(s, 4);
00194 avio_wb32(s, 0x39);
00195
00196 switch(sample_rate) {
00197 case 48000:
00198 case 24000:
00199 case 12000:
00200 fscode = 1;
00201 break;
00202 default:
00203 case 44100:
00204 case 22050:
00205 case 11025:
00206 fscode = 2;
00207 break;
00208 case 32000:
00209 case 16000:
00210 case 8000:
00211 fscode = 3;
00212 }
00213 avio_wb16(s, fscode);
00214
00215
00216 if (coded_frame_size == 557)
00217 coded_frame_size--;
00218 avio_wb32(s, coded_frame_size);
00219 avio_wb32(s, 0x51540);
00220 avio_wb32(s, 0x249f0);
00221 avio_wb32(s, 0x249f0);
00222 avio_wb16(s, 0x01);
00223
00224 avio_wb16(s, coded_frame_size);
00225 avio_wb32(s, 0);
00226 avio_wb16(s, stream->enc->sample_rate);
00227 avio_wb32(s, 0x10);
00228 avio_wb16(s, stream->enc->channels);
00229 put_str8(s, "Int0");
00230 if (stream->enc->codec_tag) {
00231 avio_w8(s, 4);
00232 avio_wl32(s, stream->enc->codec_tag);
00233 } else {
00234 av_log(ctx, AV_LOG_ERROR, "Invalid codec tag\n");
00235 return -1;
00236 }
00237 avio_wb16(s, 0);
00238 avio_wb16(s, 0);
00239 avio_wb16(s, 0);
00240 avio_w8(s, 0);
00241 } else {
00242
00243 avio_wb32(s,34);
00244 ffio_wfourcc(s, "VIDO");
00245 if(stream->enc->codec_id == AV_CODEC_ID_RV10)
00246 ffio_wfourcc(s,"RV10");
00247 else
00248 ffio_wfourcc(s,"RV20");
00249 avio_wb16(s, stream->enc->width);
00250 avio_wb16(s, stream->enc->height);
00251 avio_wb16(s, (int) stream->frame_rate);
00252 avio_wb32(s,0);
00253 avio_wb16(s, (int) stream->frame_rate);
00254 avio_wb32(s,0);
00255 avio_wb16(s, 8);
00256
00257
00258
00259 if(stream->enc->codec_id == AV_CODEC_ID_RV10)
00260 avio_wb32(s,0x10000000);
00261 else
00262 avio_wb32(s,0x20103001);
00263
00264 }
00265 }
00266
00267
00268 data_pos = s->buf_ptr - start_ptr;
00269 rm->data_pos = data_pos;
00270 data_offset_ptr[0] = data_pos >> 24;
00271 data_offset_ptr[1] = data_pos >> 16;
00272 data_offset_ptr[2] = data_pos >> 8;
00273 data_offset_ptr[3] = data_pos;
00274
00275
00276 ffio_wfourcc(s, "DATA");
00277 avio_wb32(s,data_size + 10 + 8);
00278 avio_wb16(s,0);
00279
00280 avio_wb32(s, nb_packets);
00281 avio_wb32(s,0);
00282 return 0;
00283 }
00284
00285 static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream,
00286 int length, int key_frame)
00287 {
00288 int timestamp;
00289 AVIOContext *s = ctx->pb;
00290
00291 stream->nb_packets++;
00292 stream->packet_total_size += length;
00293 if (length > stream->packet_max_size)
00294 stream->packet_max_size = length;
00295
00296 avio_wb16(s,0);
00297 avio_wb16(s,length + 12);
00298 avio_wb16(s, stream->num);
00299 timestamp = (1000 * (float)stream->nb_frames) / stream->frame_rate;
00300 avio_wb32(s, timestamp);
00301 avio_w8(s, 0);
00302 avio_w8(s, key_frame ? 2 : 0);
00303 }
00304
00305 static int rm_write_header(AVFormatContext *s)
00306 {
00307 RMMuxContext *rm = s->priv_data;
00308 StreamInfo *stream;
00309 int n;
00310 AVCodecContext *codec;
00311
00312 if (s->nb_streams > 2) {
00313 av_log(s, AV_LOG_ERROR, "At most 2 streams are currently supported for muxing in RM\n");
00314 return AVERROR_PATCHWELCOME;
00315 }
00316
00317 for(n=0;n<s->nb_streams;n++) {
00318 s->streams[n]->id = n;
00319 codec = s->streams[n]->codec;
00320 stream = &rm->streams[n];
00321 memset(stream, 0, sizeof(StreamInfo));
00322 stream->num = n;
00323 stream->bit_rate = codec->bit_rate;
00324 stream->enc = codec;
00325
00326 switch(codec->codec_type) {
00327 case AVMEDIA_TYPE_AUDIO:
00328 rm->audio_stream = stream;
00329 stream->frame_rate = (float)codec->sample_rate / (float)codec->frame_size;
00330
00331 stream->packet_max_size = 1024;
00332 stream->nb_packets = 0;
00333 stream->total_frames = stream->nb_packets;
00334 break;
00335 case AVMEDIA_TYPE_VIDEO:
00336 rm->video_stream = stream;
00337 stream->frame_rate = (float)codec->time_base.den / (float)codec->time_base.num;
00338
00339 stream->packet_max_size = 4096;
00340 stream->nb_packets = 0;
00341 stream->total_frames = stream->nb_packets;
00342 break;
00343 default:
00344 return -1;
00345 }
00346 }
00347
00348 if (rv10_write_header(s, 0, 0))
00349 return AVERROR_INVALIDDATA;
00350 avio_flush(s->pb);
00351 return 0;
00352 }
00353
00354 static int rm_write_audio(AVFormatContext *s, const uint8_t *buf, int size, int flags)
00355 {
00356 uint8_t *buf1;
00357 RMMuxContext *rm = s->priv_data;
00358 AVIOContext *pb = s->pb;
00359 StreamInfo *stream = rm->audio_stream;
00360 int i;
00361
00362
00363 buf1 = av_malloc(size * sizeof(uint8_t));
00364
00365 write_packet_header(s, stream, size, !!(flags & AV_PKT_FLAG_KEY));
00366
00367 if (stream->enc->codec_id == AV_CODEC_ID_AC3) {
00368
00369 for(i=0;i<size;i+=2) {
00370 buf1[i] = buf[i+1];
00371 buf1[i+1] = buf[i];
00372 }
00373 avio_write(pb, buf1, size);
00374 } else {
00375 avio_write(pb, buf, size);
00376 }
00377 avio_flush(pb);
00378 stream->nb_frames++;
00379 av_free(buf1);
00380 return 0;
00381 }
00382
00383 static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int flags)
00384 {
00385 RMMuxContext *rm = s->priv_data;
00386 AVIOContext *pb = s->pb;
00387 StreamInfo *stream = rm->video_stream;
00388 int key_frame = !!(flags & AV_PKT_FLAG_KEY);
00389
00390
00391
00392
00393
00394 #if 1
00395 write_packet_header(s, stream, size + 7 + (size >= 0x4000)*4, key_frame);
00396
00397 avio_w8(pb, 0x81);
00398
00399
00400 if (key_frame) {
00401 avio_w8(pb, 0x81);
00402 } else {
00403 avio_w8(pb, 0x01);
00404 }
00405 if(size >= 0x4000){
00406 avio_wb32(pb, size);
00407 avio_wb32(pb, size);
00408 }else{
00409 avio_wb16(pb, 0x4000 | size);
00410 avio_wb16(pb, 0x4000 | size);
00411 }
00412 #else
00413
00414 write_packet_header(s, size + 6);
00415 avio_w8(pb, 0xc0);
00416 avio_wb16(pb, 0x4000 + size);
00417 avio_wb16(pb, 0x4000 + packet_number * 126);
00418 #endif
00419 avio_w8(pb, stream->nb_frames & 0xff);
00420
00421 avio_write(pb, buf, size);
00422 avio_flush(pb);
00423
00424 stream->nb_frames++;
00425 return 0;
00426 }
00427
00428 static int rm_write_packet(AVFormatContext *s, AVPacket *pkt)
00429 {
00430 if (s->streams[pkt->stream_index]->codec->codec_type ==
00431 AVMEDIA_TYPE_AUDIO)
00432 return rm_write_audio(s, pkt->data, pkt->size, pkt->flags);
00433 else
00434 return rm_write_video(s, pkt->data, pkt->size, pkt->flags);
00435 }
00436
00437 static int rm_write_trailer(AVFormatContext *s)
00438 {
00439 RMMuxContext *rm = s->priv_data;
00440 int data_size, index_pos, i;
00441 AVIOContext *pb = s->pb;
00442
00443 if (s->pb->seekable) {
00444
00445 index_pos = avio_tell(pb);
00446 data_size = index_pos - rm->data_pos;
00447
00448
00449
00450
00451 avio_wb32(pb, 0);
00452 avio_wb32(pb, 0);
00453
00454 avio_seek(pb, 0, SEEK_SET);
00455 for(i=0;i<s->nb_streams;i++)
00456 rm->streams[i].total_frames = rm->streams[i].nb_frames;
00457 rv10_write_header(s, data_size, 0);
00458 } else {
00459
00460 avio_wb32(pb, 0);
00461 avio_wb32(pb, 0);
00462 }
00463
00464 return 0;
00465 }
00466
00467
00468 AVOutputFormat ff_rm_muxer = {
00469 .name = "rm",
00470 .long_name = NULL_IF_CONFIG_SMALL("RealMedia"),
00471 .mime_type = "application/vnd.rn-realmedia",
00472 .extensions = "rm,ra",
00473 .priv_data_size = sizeof(RMMuxContext),
00474 .audio_codec = AV_CODEC_ID_AC3,
00475 .video_codec = AV_CODEC_ID_RV10,
00476 .write_header = rm_write_header,
00477 .write_packet = rm_write_packet,
00478 .write_trailer = rm_write_trailer,
00479 .codec_tag = (const AVCodecTag* const []){ ff_rm_codec_tags, 0 },
00480 };