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