1/* 2 * AVI muxer 3 * Copyright (c) 2000 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 "avi.h" 23#include "riff.h" 24 25/* 26 * TODO: 27 * - fill all fields if non streamed (nb_frames for example) 28 */ 29 30typedef struct AVIIentry { 31 unsigned int flags, pos, len; 32} AVIIentry; 33 34#define AVI_INDEX_CLUSTER_SIZE 16384 35 36typedef struct AVIIndex { 37 int64_t indx_start; 38 int entry; 39 int ents_allocated; 40 AVIIentry** cluster; 41} AVIIndex; 42 43typedef struct { 44 int64_t riff_start, movi_list, odml_list; 45 int64_t frames_hdr_all, frames_hdr_strm[MAX_STREAMS]; 46 int audio_strm_length[MAX_STREAMS]; 47 int riff_id; 48 int packet_count[MAX_STREAMS]; 49 50 AVIIndex indexes[MAX_STREAMS]; 51} AVIContext; 52 53static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id) 54{ 55 int cl = ent_id / AVI_INDEX_CLUSTER_SIZE; 56 int id = ent_id % AVI_INDEX_CLUSTER_SIZE; 57 return &idx->cluster[cl][id]; 58} 59 60static int64_t avi_start_new_riff(AVIContext *avi, ByteIOContext *pb, 61 const char* riff_tag, const char* list_tag) 62{ 63 int64_t loff; 64 int i; 65 66 avi->riff_id++; 67 for (i=0; i<MAX_STREAMS; i++) 68 avi->indexes[i].entry = 0; 69 70 avi->riff_start = start_tag(pb, "RIFF"); 71 put_tag(pb, riff_tag); 72 loff = start_tag(pb, "LIST"); 73 put_tag(pb, list_tag); 74 return loff; 75} 76 77static char* avi_stream2fourcc(char* tag, int index, enum CodecType type) 78{ 79 tag[0] = '0'; 80 tag[1] = '0' + index; 81 if (type == CODEC_TYPE_VIDEO) { 82 tag[2] = 'd'; 83 tag[3] = 'c'; 84 } else { 85 tag[2] = 'w'; 86 tag[3] = 'b'; 87 } 88 tag[4] = '\0'; 89 return tag; 90} 91 92static void avi_write_info_tag(ByteIOContext *pb, const char *tag, const char *str) 93{ 94 int len = strlen(str); 95 if (len > 0) { 96 len++; 97 put_tag(pb, tag); 98 put_le32(pb, len); 99 put_strz(pb, str); 100 if (len & 1) 101 put_byte(pb, 0); 102 } 103} 104 105static void avi_write_info_tag2(AVFormatContext *s, const char *fourcc, const char *key1, const char *key2) 106{ 107 AVMetadataTag *tag= av_metadata_get(s->metadata, key1, NULL, 0); 108 if(!tag && key2) 109 tag= av_metadata_get(s->metadata, key2, NULL, 0); 110 if(tag) 111 avi_write_info_tag(s->pb, fourcc, tag->value); 112} 113 114static int avi_write_counters(AVFormatContext* s, int riff_id) 115{ 116 ByteIOContext *pb = s->pb; 117 AVIContext *avi = s->priv_data; 118 int n, au_byterate, au_ssize, au_scale, nb_frames = 0; 119 int64_t file_size; 120 AVCodecContext* stream; 121 122 file_size = url_ftell(pb); 123 for(n = 0; n < s->nb_streams; n++) { 124 assert(avi->frames_hdr_strm[n]); 125 stream = s->streams[n]->codec; 126 url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET); 127 ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); 128 if(au_ssize == 0) { 129 put_le32(pb, avi->packet_count[n]); 130 } else { 131 put_le32(pb, avi->audio_strm_length[n] / au_ssize); 132 } 133 if(stream->codec_type == CODEC_TYPE_VIDEO) 134 nb_frames = FFMAX(nb_frames, avi->packet_count[n]); 135 } 136 if(riff_id == 1) { 137 assert(avi->frames_hdr_all); 138 url_fseek(pb, avi->frames_hdr_all, SEEK_SET); 139 put_le32(pb, nb_frames); 140 } 141 url_fseek(pb, file_size, SEEK_SET); 142 143 return 0; 144} 145 146static int avi_write_header(AVFormatContext *s) 147{ 148 AVIContext *avi = s->priv_data; 149 ByteIOContext *pb = s->pb; 150 int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; 151 AVCodecContext *stream, *video_enc; 152 int64_t list1, list2, strh, strf; 153 154 /* header list */ 155 avi->riff_id = 0; 156 list1 = avi_start_new_riff(avi, pb, "AVI ", "hdrl"); 157 158 /* avi header */ 159 put_tag(pb, "avih"); 160 put_le32(pb, 14 * 4); 161 bitrate = 0; 162 163 video_enc = NULL; 164 for(n=0;n<s->nb_streams;n++) { 165 stream = s->streams[n]->codec; 166 bitrate += stream->bit_rate; 167 if (stream->codec_type == CODEC_TYPE_VIDEO) 168 video_enc = stream; 169 } 170 171 nb_frames = 0; 172 173 if(video_enc){ 174 put_le32(pb, (uint32_t)(INT64_C(1000000) * video_enc->time_base.num / video_enc->time_base.den)); 175 } else { 176 put_le32(pb, 0); 177 } 178 put_le32(pb, bitrate / 8); /* XXX: not quite exact */ 179 put_le32(pb, 0); /* padding */ 180 if (url_is_streamed(pb)) 181 put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ 182 else 183 put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ 184 avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */ 185 put_le32(pb, nb_frames); /* nb frames, filled later */ 186 put_le32(pb, 0); /* initial frame */ 187 put_le32(pb, s->nb_streams); /* nb streams */ 188 put_le32(pb, 1024 * 1024); /* suggested buffer size */ 189 if(video_enc){ 190 put_le32(pb, video_enc->width); 191 put_le32(pb, video_enc->height); 192 } else { 193 put_le32(pb, 0); 194 put_le32(pb, 0); 195 } 196 put_le32(pb, 0); /* reserved */ 197 put_le32(pb, 0); /* reserved */ 198 put_le32(pb, 0); /* reserved */ 199 put_le32(pb, 0); /* reserved */ 200 201 /* stream list */ 202 for(i=0;i<n;i++) { 203 list2 = start_tag(pb, "LIST"); 204 put_tag(pb, "strl"); 205 206 stream = s->streams[i]->codec; 207 208 /* stream generic header */ 209 strh = start_tag(pb, "strh"); 210 switch(stream->codec_type) { 211 case CODEC_TYPE_VIDEO: put_tag(pb, "vids"); break; 212 case CODEC_TYPE_AUDIO: put_tag(pb, "auds"); break; 213// case CODEC_TYPE_TEXT : put_tag(pb, "txts"); break; 214 case CODEC_TYPE_DATA : put_tag(pb, "dats"); break; 215 } 216 if(stream->codec_type == CODEC_TYPE_VIDEO) 217 put_le32(pb, stream->codec_tag); 218 else 219 put_le32(pb, 1); 220 put_le32(pb, 0); /* flags */ 221 put_le16(pb, 0); /* priority */ 222 put_le16(pb, 0); /* language */ 223 put_le32(pb, 0); /* initial frame */ 224 225 ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); 226 227 put_le32(pb, au_scale); /* scale */ 228 put_le32(pb, au_byterate); /* rate */ 229 av_set_pts_info(s->streams[i], 64, au_scale, au_byterate); 230 231 put_le32(pb, 0); /* start */ 232 avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ 233 if (url_is_streamed(pb)) 234 put_le32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ 235 else 236 put_le32(pb, 0); /* length, XXX: filled later */ 237 238 /* suggested buffer size */ //FIXME set at the end to largest chunk 239 if(stream->codec_type == CODEC_TYPE_VIDEO) 240 put_le32(pb, 1024 * 1024); 241 else if(stream->codec_type == CODEC_TYPE_AUDIO) 242 put_le32(pb, 12 * 1024); 243 else 244 put_le32(pb, 0); 245 put_le32(pb, -1); /* quality */ 246 put_le32(pb, au_ssize); /* sample size */ 247 put_le32(pb, 0); 248 put_le16(pb, stream->width); 249 put_le16(pb, stream->height); 250 end_tag(pb, strh); 251 252 if(stream->codec_type != CODEC_TYPE_DATA){ 253 strf = start_tag(pb, "strf"); 254 switch(stream->codec_type) { 255 case CODEC_TYPE_VIDEO: 256 put_bmp_header(pb, stream, codec_bmp_tags, 0); 257 break; 258 case CODEC_TYPE_AUDIO: 259 if (put_wav_header(pb, stream) < 0) { 260 return -1; 261 } 262 break; 263 default: 264 return -1; 265 } 266 end_tag(pb, strf); 267 } 268 269 if (!url_is_streamed(pb)) { 270 unsigned char tag[5]; 271 int j; 272 273 /* Starting to lay out AVI OpenDML master index. 274 * We want to make it JUNK entry for now, since we'd 275 * like to get away without making AVI an OpenDML one 276 * for compatibility reasons. 277 */ 278 avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0; 279 avi->indexes[i].indx_start = start_tag(pb, "JUNK"); 280 put_le16(pb, 4); /* wLongsPerEntry */ 281 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ 282 put_byte(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ 283 put_le32(pb, 0); /* nEntriesInUse (will fill out later on) */ 284 put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type)); 285 /* dwChunkId */ 286 put_le64(pb, 0); /* dwReserved[3] 287 put_le32(pb, 0); Must be 0. */ 288 for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) 289 put_le64(pb, 0); 290 end_tag(pb, avi->indexes[i].indx_start); 291 } 292 293 if( stream->codec_type == CODEC_TYPE_VIDEO 294 && s->streams[i]->sample_aspect_ratio.num>0 295 && s->streams[i]->sample_aspect_ratio.den>0){ 296 int vprp= start_tag(pb, "vprp"); 297 AVRational dar = av_mul_q(s->streams[i]->sample_aspect_ratio, 298 (AVRational){stream->width, stream->height}); 299 int num, den; 300 av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); 301 302 put_le32(pb, 0); //video format = unknown 303 put_le32(pb, 0); //video standard= unknown 304 put_le32(pb, lrintf(1.0/av_q2d(stream->time_base))); 305 put_le32(pb, stream->width ); 306 put_le32(pb, stream->height); 307 put_le16(pb, den); 308 put_le16(pb, num); 309 put_le32(pb, stream->width ); 310 put_le32(pb, stream->height); 311 put_le32(pb, 1); //progressive FIXME 312 313 put_le32(pb, stream->height); 314 put_le32(pb, stream->width ); 315 put_le32(pb, stream->height); 316 put_le32(pb, stream->width ); 317 put_le32(pb, 0); 318 put_le32(pb, 0); 319 320 put_le32(pb, 0); 321 put_le32(pb, 0); 322 end_tag(pb, vprp); 323 } 324 325 end_tag(pb, list2); 326 } 327 328 if (!url_is_streamed(pb)) { 329 /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ 330 avi->odml_list = start_tag(pb, "JUNK"); 331 put_tag(pb, "odml"); 332 put_tag(pb, "dmlh"); 333 put_le32(pb, 248); 334 for (i = 0; i < 248; i+= 4) 335 put_le32(pb, 0); 336 end_tag(pb, avi->odml_list); 337 } 338 339 end_tag(pb, list1); 340 341 list2 = start_tag(pb, "LIST"); 342 put_tag(pb, "INFO"); 343 avi_write_info_tag2(s, "INAM", "Title", NULL); 344 avi_write_info_tag2(s, "IART", "Artist", "Author"); 345 avi_write_info_tag2(s, "ICOP", "Copyright", NULL); 346 avi_write_info_tag2(s, "ICMT", "Comment", NULL); 347 avi_write_info_tag2(s, "IPRD", "Album", NULL); 348 avi_write_info_tag2(s, "IGNR", "Genre", NULL); 349 avi_write_info_tag2(s, "IPRT", "Track", NULL); 350 if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) 351 avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); 352 end_tag(pb, list2); 353 354 /* some padding for easier tag editing */ 355 list2 = start_tag(pb, "JUNK"); 356 for (i = 0; i < 1016; i += 4) 357 put_le32(pb, 0); 358 end_tag(pb, list2); 359 360 avi->movi_list = start_tag(pb, "LIST"); 361 put_tag(pb, "movi"); 362 363 put_flush_packet(pb); 364 365 return 0; 366} 367 368static int avi_write_ix(AVFormatContext *s) 369{ 370 ByteIOContext *pb = s->pb; 371 AVIContext *avi = s->priv_data; 372 char tag[5]; 373 char ix_tag[] = "ix00"; 374 int i, j; 375 376 assert(!url_is_streamed(pb)); 377 378 if (avi->riff_id > AVI_MASTER_INDEX_SIZE) 379 return -1; 380 381 for (i=0;i<s->nb_streams;i++) { 382 int64_t ix, pos; 383 384 avi_stream2fourcc(&tag[0], i, s->streams[i]->codec->codec_type); 385 ix_tag[3] = '0' + i; 386 387 /* Writing AVI OpenDML leaf index chunk */ 388 ix = url_ftell(pb); 389 put_tag(pb, &ix_tag[0]); /* ix?? */ 390 put_le32(pb, avi->indexes[i].entry * 8 + 24); 391 /* chunk size */ 392 put_le16(pb, 2); /* wLongsPerEntry */ 393 put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ 394 put_byte(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ 395 put_le32(pb, avi->indexes[i].entry); 396 /* nEntriesInUse */ 397 put_tag(pb, &tag[0]); /* dwChunkId */ 398 put_le64(pb, avi->movi_list);/* qwBaseOffset */ 399 put_le32(pb, 0); /* dwReserved_3 (must be 0) */ 400 401 for (j=0; j<avi->indexes[i].entry; j++) { 402 AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j); 403 put_le32(pb, ie->pos + 8); 404 put_le32(pb, ((uint32_t)ie->len & ~0x80000000) | 405 (ie->flags & 0x10 ? 0 : 0x80000000)); 406 } 407 put_flush_packet(pb); 408 pos = url_ftell(pb); 409 410 /* Updating one entry in the AVI OpenDML master index */ 411 url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET); 412 put_tag(pb, "indx"); /* enabling this entry */ 413 url_fskip(pb, 8); 414 put_le32(pb, avi->riff_id); /* nEntriesInUse */ 415 url_fskip(pb, 16*avi->riff_id); 416 put_le64(pb, ix); /* qwOffset */ 417 put_le32(pb, pos - ix); /* dwSize */ 418 put_le32(pb, avi->indexes[i].entry); /* dwDuration */ 419 420 url_fseek(pb, pos, SEEK_SET); 421 } 422 return 0; 423} 424 425static int avi_write_idx1(AVFormatContext *s) 426{ 427 ByteIOContext *pb = s->pb; 428 AVIContext *avi = s->priv_data; 429 int64_t idx_chunk; 430 int i; 431 char tag[5]; 432 433 if (!url_is_streamed(pb)) { 434 AVIIentry* ie = 0, *tie; 435 int entry[MAX_STREAMS]; 436 int empty, stream_id = -1; 437 438 idx_chunk = start_tag(pb, "idx1"); 439 memset(&entry[0], 0, sizeof(entry)); 440 do { 441 empty = 1; 442 for (i=0; i<s->nb_streams; i++) { 443 if (avi->indexes[i].entry <= entry[i]) 444 continue; 445 446 tie = avi_get_ientry(&avi->indexes[i], entry[i]); 447 if (empty || tie->pos < ie->pos) { 448 ie = tie; 449 stream_id = i; 450 } 451 empty = 0; 452 } 453 if (!empty) { 454 avi_stream2fourcc(&tag[0], stream_id, 455 s->streams[stream_id]->codec->codec_type); 456 put_tag(pb, &tag[0]); 457 put_le32(pb, ie->flags); 458 put_le32(pb, ie->pos); 459 put_le32(pb, ie->len); 460 entry[stream_id]++; 461 } 462 } while (!empty); 463 end_tag(pb, idx_chunk); 464 465 avi_write_counters(s, avi->riff_id); 466 } 467 return 0; 468} 469 470static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) 471{ 472 AVIContext *avi = s->priv_data; 473 ByteIOContext *pb = s->pb; 474 unsigned char tag[5]; 475 unsigned int flags=0; 476 const int stream_index= pkt->stream_index; 477 AVCodecContext *enc= s->streams[stream_index]->codec; 478 int size= pkt->size; 479 480// av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index); 481 while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){ 482 AVPacket empty_packet; 483 484 av_init_packet(&empty_packet); 485 empty_packet.size= 0; 486 empty_packet.data= NULL; 487 empty_packet.stream_index= stream_index; 488 avi_write_packet(s, &empty_packet); 489// av_log(s, AV_LOG_DEBUG, "dup %"PRId64" %d\n", pkt->dts, avi->packet_count[stream_index]); 490 } 491 avi->packet_count[stream_index]++; 492 493 // Make sure to put an OpenDML chunk when the file size exceeds the limits 494 if (!url_is_streamed(pb) && 495 (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { 496 497 avi_write_ix(s); 498 end_tag(pb, avi->movi_list); 499 500 if (avi->riff_id == 1) 501 avi_write_idx1(s); 502 503 end_tag(pb, avi->riff_start); 504 avi->movi_list = avi_start_new_riff(avi, pb, "AVIX", "movi"); 505 } 506 507 avi_stream2fourcc(&tag[0], stream_index, enc->codec_type); 508 if(pkt->flags&PKT_FLAG_KEY) 509 flags = 0x10; 510 if (enc->codec_type == CODEC_TYPE_AUDIO) { 511 avi->audio_strm_length[stream_index] += size; 512 } 513 514 if (!url_is_streamed(s->pb)) { 515 AVIIndex* idx = &avi->indexes[stream_index]; 516 int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; 517 int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; 518 if (idx->ents_allocated <= idx->entry) { 519 idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); 520 if (!idx->cluster) 521 return -1; 522 idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); 523 if (!idx->cluster[cl]) 524 return -1; 525 idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; 526 } 527 528 idx->cluster[cl][id].flags = flags; 529 idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list; 530 idx->cluster[cl][id].len = size; 531 idx->entry++; 532 } 533 534 put_buffer(pb, tag, 4); 535 put_le32(pb, size); 536 put_buffer(pb, pkt->data, size); 537 if (size & 1) 538 put_byte(pb, 0); 539 540 put_flush_packet(pb); 541 return 0; 542} 543 544static int avi_write_trailer(AVFormatContext *s) 545{ 546 AVIContext *avi = s->priv_data; 547 ByteIOContext *pb = s->pb; 548 int res = 0; 549 int i, j, n, nb_frames; 550 int64_t file_size; 551 552 if (!url_is_streamed(pb)){ 553 if (avi->riff_id == 1) { 554 end_tag(pb, avi->movi_list); 555 res = avi_write_idx1(s); 556 end_tag(pb, avi->riff_start); 557 } else { 558 avi_write_ix(s); 559 end_tag(pb, avi->movi_list); 560 end_tag(pb, avi->riff_start); 561 562 file_size = url_ftell(pb); 563 url_fseek(pb, avi->odml_list - 8, SEEK_SET); 564 put_tag(pb, "LIST"); /* Making this AVI OpenDML one */ 565 url_fskip(pb, 16); 566 567 for (n=nb_frames=0;n<s->nb_streams;n++) { 568 AVCodecContext *stream = s->streams[n]->codec; 569 if (stream->codec_type == CODEC_TYPE_VIDEO) { 570 if (nb_frames < avi->packet_count[n]) 571 nb_frames = avi->packet_count[n]; 572 } else { 573 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) { 574 nb_frames += avi->packet_count[n]; 575 } 576 } 577 } 578 put_le32(pb, nb_frames); 579 url_fseek(pb, file_size, SEEK_SET); 580 581 avi_write_counters(s, avi->riff_id); 582 } 583 } 584 put_flush_packet(pb); 585 586 for (i=0; i<MAX_STREAMS; i++) { 587 for (j=0; j<avi->indexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) 588 av_free(avi->indexes[i].cluster[j]); 589 av_free(avi->indexes[i].cluster); 590 avi->indexes[i].cluster = NULL; 591 avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0; 592 } 593 594 return res; 595} 596 597AVOutputFormat avi_muxer = { 598 "avi", 599 NULL_IF_CONFIG_SMALL("AVI format"), 600 "video/x-msvideo", 601 "avi", 602 sizeof(AVIContext), 603 CODEC_ID_MP2, 604 CODEC_ID_MPEG4, 605 avi_write_header, 606 avi_write_packet, 607 avi_write_trailer, 608 .codec_tag= (const AVCodecTag* const []){codec_bmp_tags, codec_wav_tags, 0}, 609 .flags= AVFMT_VARIABLE_FPS, 610}; 611