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 "avi.h"
00023 #include "riff.h"
00024
00025
00026
00027
00028
00029
00030 #ifdef CONFIG_AVI_MUXER
00031 typedef struct AVIIentry {
00032 unsigned int flags, pos, len;
00033 } AVIIentry;
00034
00035 #define AVI_INDEX_CLUSTER_SIZE 16384
00036
00037 typedef struct AVIIndex {
00038 offset_t indx_start;
00039 int entry;
00040 int ents_allocated;
00041 AVIIentry** cluster;
00042 } AVIIndex;
00043
00044 typedef struct {
00045 offset_t riff_start, movi_list, odml_list;
00046 offset_t frames_hdr_all, frames_hdr_strm[MAX_STREAMS];
00047 int audio_strm_length[MAX_STREAMS];
00048 int riff_id;
00049 int packet_count[MAX_STREAMS];
00050
00051 AVIIndex indexes[MAX_STREAMS];
00052 } AVIContext;
00053
00054 static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id)
00055 {
00056 int cl = ent_id / AVI_INDEX_CLUSTER_SIZE;
00057 int id = ent_id % AVI_INDEX_CLUSTER_SIZE;
00058 return &idx->cluster[cl][id];
00059 }
00060
00061 static offset_t avi_start_new_riff(AVIContext *avi, ByteIOContext *pb,
00062 const char* riff_tag, const char* list_tag)
00063 {
00064 offset_t loff;
00065 int i;
00066
00067 avi->riff_id++;
00068 for (i=0; i<MAX_STREAMS; i++)
00069 avi->indexes[i].entry = 0;
00070
00071 avi->riff_start = start_tag(pb, "RIFF");
00072 put_tag(pb, riff_tag);
00073 loff = start_tag(pb, "LIST");
00074 put_tag(pb, list_tag);
00075 return loff;
00076 }
00077
00078 static char* avi_stream2fourcc(char* tag, int index, enum CodecType type)
00079 {
00080 tag[0] = '0';
00081 tag[1] = '0' + index;
00082 if (type == CODEC_TYPE_VIDEO) {
00083 tag[2] = 'd';
00084 tag[3] = 'c';
00085 } else {
00086 tag[2] = 'w';
00087 tag[3] = 'b';
00088 }
00089 tag[4] = '\0';
00090 return tag;
00091 }
00092
00093 static void avi_write_info_tag(ByteIOContext *pb, const char *tag, const char *str)
00094 {
00095 int len = strlen(str);
00096 if (len > 0) {
00097 len++;
00098 put_tag(pb, tag);
00099 put_le32(pb, len);
00100 put_strz(pb, str);
00101 if (len & 1)
00102 put_byte(pb, 0);
00103 }
00104 }
00105
00106 static int avi_write_counters(AVFormatContext* s, int riff_id)
00107 {
00108 ByteIOContext *pb = s->pb;
00109 AVIContext *avi = s->priv_data;
00110 int n, au_byterate, au_ssize, au_scale, nb_frames = 0;
00111 offset_t file_size;
00112 AVCodecContext* stream;
00113
00114 file_size = url_ftell(pb);
00115 for(n = 0; n < s->nb_streams; n++) {
00116 assert(avi->frames_hdr_strm[n]);
00117 stream = s->streams[n]->codec;
00118 url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET);
00119 ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
00120 if(au_ssize == 0) {
00121 put_le32(pb, avi->packet_count[n]);
00122 } else {
00123 put_le32(pb, avi->audio_strm_length[n] / au_ssize);
00124 }
00125 if(stream->codec_type == CODEC_TYPE_VIDEO)
00126 nb_frames = FFMAX(nb_frames, avi->packet_count[n]);
00127 }
00128 if(riff_id == 1) {
00129 assert(avi->frames_hdr_all);
00130 url_fseek(pb, avi->frames_hdr_all, SEEK_SET);
00131 put_le32(pb, nb_frames);
00132 }
00133 url_fseek(pb, file_size, SEEK_SET);
00134
00135 return 0;
00136 }
00137
00138 static int avi_write_header(AVFormatContext *s)
00139 {
00140 AVIContext *avi = s->priv_data;
00141 ByteIOContext *pb = s->pb;
00142 int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
00143 AVCodecContext *stream, *video_enc;
00144 offset_t list1, list2, strh, strf;
00145
00146
00147 avi->riff_id = 0;
00148 list1 = avi_start_new_riff(avi, pb, "AVI ", "hdrl");
00149
00150
00151 put_tag(pb, "avih");
00152 put_le32(pb, 14 * 4);
00153 bitrate = 0;
00154
00155 video_enc = NULL;
00156 for(n=0;n<s->nb_streams;n++) {
00157 stream = s->streams[n]->codec;
00158 bitrate += stream->bit_rate;
00159 if (stream->codec_type == CODEC_TYPE_VIDEO)
00160 video_enc = stream;
00161 }
00162
00163 nb_frames = 0;
00164
00165 if(video_enc){
00166 put_le32(pb, (uint32_t)(INT64_C(1000000) * video_enc->time_base.num / video_enc->time_base.den));
00167 } else {
00168 put_le32(pb, 0);
00169 }
00170 put_le32(pb, bitrate / 8);
00171 put_le32(pb, 0);
00172 if (url_is_streamed(pb))
00173 put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED);
00174 else
00175 put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED);
00176 avi->frames_hdr_all = url_ftell(pb);
00177 put_le32(pb, nb_frames);
00178 put_le32(pb, 0);
00179 put_le32(pb, s->nb_streams);
00180 put_le32(pb, 1024 * 1024);
00181 if(video_enc){
00182 put_le32(pb, video_enc->width);
00183 put_le32(pb, video_enc->height);
00184 } else {
00185 put_le32(pb, 0);
00186 put_le32(pb, 0);
00187 }
00188 put_le32(pb, 0);
00189 put_le32(pb, 0);
00190 put_le32(pb, 0);
00191 put_le32(pb, 0);
00192
00193
00194 for(i=0;i<n;i++) {
00195 list2 = start_tag(pb, "LIST");
00196 put_tag(pb, "strl");
00197
00198 stream = s->streams[i]->codec;
00199
00200
00201 strh = start_tag(pb, "strh");
00202 switch(stream->codec_type) {
00203 case CODEC_TYPE_VIDEO: put_tag(pb, "vids"); break;
00204 case CODEC_TYPE_AUDIO: put_tag(pb, "auds"); break;
00205
00206 case CODEC_TYPE_DATA : put_tag(pb, "dats"); break;
00207 }
00208 if(stream->codec_type == CODEC_TYPE_VIDEO)
00209 put_le32(pb, stream->codec_tag);
00210 else
00211 put_le32(pb, 1);
00212 put_le32(pb, 0);
00213 put_le16(pb, 0);
00214 put_le16(pb, 0);
00215 put_le32(pb, 0);
00216
00217 ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
00218
00219 put_le32(pb, au_scale);
00220 put_le32(pb, au_byterate);
00221 av_set_pts_info(s->streams[i], 64, au_scale, au_byterate);
00222
00223 put_le32(pb, 0);
00224 avi->frames_hdr_strm[i] = url_ftell(pb);
00225 if (url_is_streamed(pb))
00226 put_le32(pb, AVI_MAX_RIFF_SIZE);
00227 else
00228 put_le32(pb, 0);
00229
00230
00231 if(stream->codec_type == CODEC_TYPE_VIDEO)
00232 put_le32(pb, 1024 * 1024);
00233 else if(stream->codec_type == CODEC_TYPE_AUDIO)
00234 put_le32(pb, 12 * 1024);
00235 else
00236 put_le32(pb, 0);
00237 put_le32(pb, -1);
00238 put_le32(pb, au_ssize);
00239 put_le32(pb, 0);
00240 put_le16(pb, stream->width);
00241 put_le16(pb, stream->height);
00242 end_tag(pb, strh);
00243
00244 if(stream->codec_type != CODEC_TYPE_DATA){
00245 strf = start_tag(pb, "strf");
00246 switch(stream->codec_type) {
00247 case CODEC_TYPE_VIDEO:
00248 put_bmp_header(pb, stream, codec_bmp_tags, 0);
00249 break;
00250 case CODEC_TYPE_AUDIO:
00251 if (put_wav_header(pb, stream) < 0) {
00252 av_free(avi);
00253 return -1;
00254 }
00255 break;
00256 default:
00257 return -1;
00258 }
00259 end_tag(pb, strf);
00260 }
00261
00262 if (!url_is_streamed(pb)) {
00263 unsigned char tag[5];
00264 int j;
00265
00266
00267
00268
00269
00270
00271 avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0;
00272 avi->indexes[i].indx_start = start_tag(pb, "JUNK");
00273 put_le16(pb, 4);
00274 put_byte(pb, 0);
00275 put_byte(pb, 0);
00276 put_le32(pb, 0);
00277 put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type));
00278
00279 put_le64(pb, 0);
00280
00281 for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
00282 put_le64(pb, 0);
00283 end_tag(pb, avi->indexes[i].indx_start);
00284 }
00285
00286 end_tag(pb, list2);
00287 }
00288
00289 if (!url_is_streamed(pb)) {
00290
00291 avi->odml_list = start_tag(pb, "JUNK");
00292 put_tag(pb, "odml");
00293 put_tag(pb, "dmlh");
00294 put_le32(pb, 248);
00295 for (i = 0; i < 248; i+= 4)
00296 put_le32(pb, 0);
00297 end_tag(pb, avi->odml_list);
00298 }
00299
00300 end_tag(pb, list1);
00301
00302 list2 = start_tag(pb, "LIST");
00303 put_tag(pb, "INFO");
00304 avi_write_info_tag(pb, "INAM", s->title);
00305 avi_write_info_tag(pb, "IART", s->author);
00306 avi_write_info_tag(pb, "ICOP", s->copyright);
00307 avi_write_info_tag(pb, "ICMT", s->comment);
00308 avi_write_info_tag(pb, "IPRD", s->album);
00309 avi_write_info_tag(pb, "IGNR", s->genre);
00310 if (s->track) {
00311 char str_track[4];
00312 snprintf(str_track, 4, "%d", s->track);
00313 avi_write_info_tag(pb, "IPRT", str_track);
00314 }
00315 if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT))
00316 avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT);
00317 end_tag(pb, list2);
00318
00319
00320 list2 = start_tag(pb, "JUNK");
00321 for (i = 0; i < 1016; i += 4)
00322 put_le32(pb, 0);
00323 end_tag(pb, list2);
00324
00325 avi->movi_list = start_tag(pb, "LIST");
00326 put_tag(pb, "movi");
00327
00328 put_flush_packet(pb);
00329
00330 return 0;
00331 }
00332
00333 static int avi_write_ix(AVFormatContext *s)
00334 {
00335 ByteIOContext *pb = s->pb;
00336 AVIContext *avi = s->priv_data;
00337 char tag[5];
00338 char ix_tag[] = "ix00";
00339 int i, j;
00340
00341 assert(!url_is_streamed(pb));
00342
00343 if (avi->riff_id > AVI_MASTER_INDEX_SIZE)
00344 return -1;
00345
00346 for (i=0;i<s->nb_streams;i++) {
00347 offset_t ix, pos;
00348
00349 avi_stream2fourcc(&tag[0], i, s->streams[i]->codec->codec_type);
00350 ix_tag[3] = '0' + i;
00351
00352
00353 ix = url_ftell(pb);
00354 put_tag(pb, &ix_tag[0]);
00355 put_le32(pb, avi->indexes[i].entry * 8 + 24);
00356
00357 put_le16(pb, 2);
00358 put_byte(pb, 0);
00359 put_byte(pb, 1);
00360 put_le32(pb, avi->indexes[i].entry);
00361
00362 put_tag(pb, &tag[0]);
00363 put_le64(pb, avi->movi_list);
00364 put_le32(pb, 0);
00365
00366 for (j=0; j<avi->indexes[i].entry; j++) {
00367 AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j);
00368 put_le32(pb, ie->pos + 8);
00369 put_le32(pb, ((uint32_t)ie->len & ~0x80000000) |
00370 (ie->flags & 0x10 ? 0 : 0x80000000));
00371 }
00372 put_flush_packet(pb);
00373 pos = url_ftell(pb);
00374
00375
00376 url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET);
00377 put_tag(pb, "indx");
00378 url_fskip(pb, 8);
00379 put_le32(pb, avi->riff_id);
00380 url_fskip(pb, 16*avi->riff_id);
00381 put_le64(pb, ix);
00382 put_le32(pb, pos - ix);
00383 put_le32(pb, avi->indexes[i].entry);
00384
00385 url_fseek(pb, pos, SEEK_SET);
00386 }
00387 return 0;
00388 }
00389
00390 static int avi_write_idx1(AVFormatContext *s)
00391 {
00392 ByteIOContext *pb = s->pb;
00393 AVIContext *avi = s->priv_data;
00394 offset_t idx_chunk;
00395 int i;
00396 char tag[5];
00397
00398 if (!url_is_streamed(pb)) {
00399 AVIIentry* ie = 0, *tie;
00400 int entry[MAX_STREAMS];
00401 int empty, stream_id = -1;
00402
00403 idx_chunk = start_tag(pb, "idx1");
00404 memset(&entry[0], 0, sizeof(entry));
00405 do {
00406 empty = 1;
00407 for (i=0; i<s->nb_streams; i++) {
00408 if (avi->indexes[i].entry <= entry[i])
00409 continue;
00410
00411 tie = avi_get_ientry(&avi->indexes[i], entry[i]);
00412 if (empty || tie->pos < ie->pos) {
00413 ie = tie;
00414 stream_id = i;
00415 }
00416 empty = 0;
00417 }
00418 if (!empty) {
00419 avi_stream2fourcc(&tag[0], stream_id,
00420 s->streams[stream_id]->codec->codec_type);
00421 put_tag(pb, &tag[0]);
00422 put_le32(pb, ie->flags);
00423 put_le32(pb, ie->pos);
00424 put_le32(pb, ie->len);
00425 entry[stream_id]++;
00426 }
00427 } while (!empty);
00428 end_tag(pb, idx_chunk);
00429
00430 avi_write_counters(s, avi->riff_id);
00431 }
00432 return 0;
00433 }
00434
00435 static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
00436 {
00437 AVIContext *avi = s->priv_data;
00438 ByteIOContext *pb = s->pb;
00439 unsigned char tag[5];
00440 unsigned int flags=0;
00441 const int stream_index= pkt->stream_index;
00442 AVCodecContext *enc= s->streams[stream_index]->codec;
00443 int size= pkt->size;
00444
00445
00446 while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){
00447 AVPacket empty_packet;
00448
00449 av_init_packet(&empty_packet);
00450 empty_packet.size= 0;
00451 empty_packet.data= NULL;
00452 empty_packet.stream_index= stream_index;
00453 avi_write_packet(s, &empty_packet);
00454
00455 }
00456 avi->packet_count[stream_index]++;
00457
00458
00459 if (!url_is_streamed(pb) &&
00460 (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) {
00461
00462 avi_write_ix(s);
00463 end_tag(pb, avi->movi_list);
00464
00465 if (avi->riff_id == 1)
00466 avi_write_idx1(s);
00467
00468 end_tag(pb, avi->riff_start);
00469 avi->movi_list = avi_start_new_riff(avi, pb, "AVIX", "movi");
00470 }
00471
00472 avi_stream2fourcc(&tag[0], stream_index, enc->codec_type);
00473 if(pkt->flags&PKT_FLAG_KEY)
00474 flags = 0x10;
00475 if (enc->codec_type == CODEC_TYPE_AUDIO) {
00476 avi->audio_strm_length[stream_index] += size;
00477 }
00478
00479 if (!url_is_streamed(s->pb)) {
00480 AVIIndex* idx = &avi->indexes[stream_index];
00481 int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE;
00482 int id = idx->entry % AVI_INDEX_CLUSTER_SIZE;
00483 if (idx->ents_allocated <= idx->entry) {
00484 idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*));
00485 if (!idx->cluster)
00486 return -1;
00487 idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry));
00488 if (!idx->cluster[cl])
00489 return -1;
00490 idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE;
00491 }
00492
00493 idx->cluster[cl][id].flags = flags;
00494 idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list;
00495 idx->cluster[cl][id].len = size;
00496 idx->entry++;
00497 }
00498
00499 put_buffer(pb, tag, 4);
00500 put_le32(pb, size);
00501 put_buffer(pb, pkt->data, size);
00502 if (size & 1)
00503 put_byte(pb, 0);
00504
00505 put_flush_packet(pb);
00506 return 0;
00507 }
00508
00509 static int avi_write_trailer(AVFormatContext *s)
00510 {
00511 AVIContext *avi = s->priv_data;
00512 ByteIOContext *pb = s->pb;
00513 int res = 0;
00514 int i, j, n, nb_frames;
00515 offset_t file_size;
00516
00517 if (!url_is_streamed(pb)){
00518 if (avi->riff_id == 1) {
00519 end_tag(pb, avi->movi_list);
00520 res = avi_write_idx1(s);
00521 end_tag(pb, avi->riff_start);
00522 } else {
00523 avi_write_ix(s);
00524 end_tag(pb, avi->movi_list);
00525 end_tag(pb, avi->riff_start);
00526
00527 file_size = url_ftell(pb);
00528 url_fseek(pb, avi->odml_list - 8, SEEK_SET);
00529 put_tag(pb, "LIST");
00530 url_fskip(pb, 16);
00531
00532 for (n=nb_frames=0;n<s->nb_streams;n++) {
00533 AVCodecContext *stream = s->streams[n]->codec;
00534 if (stream->codec_type == CODEC_TYPE_VIDEO) {
00535 if (nb_frames < avi->packet_count[n])
00536 nb_frames = avi->packet_count[n];
00537 } else {
00538 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) {
00539 nb_frames += avi->packet_count[n];
00540 }
00541 }
00542 }
00543 put_le32(pb, nb_frames);
00544 url_fseek(pb, file_size, SEEK_SET);
00545
00546 avi_write_counters(s, avi->riff_id);
00547 }
00548 }
00549 put_flush_packet(pb);
00550
00551 for (i=0; i<MAX_STREAMS; i++) {
00552 for (j=0; j<avi->indexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++)
00553 av_free(avi->indexes[i].cluster[j]);
00554 av_free(avi->indexes[i].cluster);
00555 avi->indexes[i].cluster = NULL;
00556 avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0;
00557 }
00558
00559 return res;
00560 }
00561
00562 AVOutputFormat avi_muxer = {
00563 "avi",
00564 "avi format",
00565 "video/x-msvideo",
00566 "avi",
00567 sizeof(AVIContext),
00568 CODEC_ID_MP2,
00569 CODEC_ID_MPEG4,
00570 avi_write_header,
00571 avi_write_packet,
00572 avi_write_trailer,
00573 .codec_tag= (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, 0},
00574 };
00575 #endif //CONFIG_AVI_MUXER