FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
avienc.c
Go to the documentation of this file.
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 
22 //#define DEBUG
23 
24 #include "avformat.h"
25 #include "internal.h"
26 #include "avi.h"
27 #include "avio_internal.h"
28 #include "riff.h"
29 #include "libavutil/intreadwrite.h"
30 #include "libavutil/dict.h"
31 #include "libavutil/avassert.h"
32 #include "libavutil/timestamp.h"
33 
34 /*
35  * TODO:
36  * - fill all fields if non streamed (nb_frames for example)
37  */
38 
39 typedef struct AVIIentry {
40  unsigned int flags, pos, len;
41 } AVIIentry;
42 
43 #define AVI_INDEX_CLUSTER_SIZE 16384
44 
45 typedef struct AVIIndex {
46  int64_t indx_start;
47  int entry;
50 } AVIIndex;
51 
52 typedef struct {
53  int64_t riff_start, movi_list, odml_list;
54  int64_t frames_hdr_all;
55  int riff_id;
56 } AVIContext;
57 
58 typedef struct {
59  int64_t frames_hdr_strm;
62  int entry;
63 
65 } AVIStream ;
66 
67 static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id)
68 {
69  int cl = ent_id / AVI_INDEX_CLUSTER_SIZE;
70  int id = ent_id % AVI_INDEX_CLUSTER_SIZE;
71  return &idx->cluster[cl][id];
72 }
73 
75  const char* riff_tag, const char* list_tag)
76 {
77  AVIContext *avi= s->priv_data;
78  int64_t loff;
79  int i;
80 
81  avi->riff_id++;
82  for (i=0; i<s->nb_streams; i++){
83  AVIStream *avist= s->streams[i]->priv_data;
84  avist->indexes.entry = 0;
85  }
86 
87  avi->riff_start = ff_start_tag(pb, "RIFF");
88  ffio_wfourcc(pb, riff_tag);
89  loff = ff_start_tag(pb, "LIST");
90  ffio_wfourcc(pb, list_tag);
91  return loff;
92 }
93 
94 static char* avi_stream2fourcc(char* tag, int index, enum AVMediaType type)
95 {
96  tag[0] = '0' + index/10;
97  tag[1] = '0' + index%10;
98  if (type == AVMEDIA_TYPE_VIDEO) {
99  tag[2] = 'd';
100  tag[3] = 'c';
101  } else if (type == AVMEDIA_TYPE_SUBTITLE) {
102  // note: this is not an official code
103  tag[2] = 's';
104  tag[3] = 'b';
105  } else {
106  tag[2] = 'w';
107  tag[3] = 'b';
108  }
109  tag[4] = '\0';
110  return tag;
111 }
112 
113 static int avi_write_counters(AVFormatContext* s, int riff_id)
114 {
115  AVIOContext *pb = s->pb;
116  AVIContext *avi = s->priv_data;
117  int n, au_byterate, au_ssize, au_scale, nb_frames = 0;
118  int64_t file_size;
119  AVCodecContext* stream;
120 
121  file_size = avio_tell(pb);
122  for(n = 0; n < s->nb_streams; n++) {
123  AVIStream *avist= s->streams[n]->priv_data;
124 
125  av_assert0(avist->frames_hdr_strm);
126  stream = s->streams[n]->codec;
127  avio_seek(pb, avist->frames_hdr_strm, SEEK_SET);
128  ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
129  if(au_ssize == 0) {
130  avio_wl32(pb, avist->packet_count);
131  } else {
132  avio_wl32(pb, avist->audio_strm_length / au_ssize);
133  }
134  if(stream->codec_type == AVMEDIA_TYPE_VIDEO)
135  nb_frames = FFMAX(nb_frames, avist->packet_count);
136  }
137  if(riff_id == 1) {
139  avio_seek(pb, avi->frames_hdr_all, SEEK_SET);
140  avio_wl32(pb, nb_frames);
141  }
142  avio_seek(pb, file_size, SEEK_SET);
143 
144  return 0;
145 }
146 
148 {
149  AVIContext *avi = s->priv_data;
150  AVIOContext *pb = s->pb;
151  int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
152  AVCodecContext *stream, *video_enc;
153  int64_t list1, list2, strh, strf;
154  AVDictionaryEntry *t = NULL;
155 
156  if (s->nb_streams > AVI_MAX_STREAM_COUNT) {
157  av_log(s, AV_LOG_ERROR, "AVI does not support >%d streams\n",
159  return AVERROR(EINVAL);
160  }
161 
162  for(n=0;n<s->nb_streams;n++) {
163  s->streams[n]->priv_data= av_mallocz(sizeof(AVIStream));
164  if(!s->streams[n]->priv_data)
165  return AVERROR(ENOMEM);
166  }
167 
168  /* header list */
169  avi->riff_id = 0;
170  list1 = avi_start_new_riff(s, pb, "AVI ", "hdrl");
171 
172  /* avi header */
173  ffio_wfourcc(pb, "avih");
174  avio_wl32(pb, 14 * 4);
175  bitrate = 0;
176 
177  video_enc = NULL;
178  for(n=0;n<s->nb_streams;n++) {
179  stream = s->streams[n]->codec;
180  bitrate += stream->bit_rate;
181  if (stream->codec_type == AVMEDIA_TYPE_VIDEO)
182  video_enc = stream;
183  }
184 
185  nb_frames = 0;
186 
187  if(video_enc){
188  avio_wl32(pb, (uint32_t)(INT64_C(1000000) * video_enc->time_base.num / video_enc->time_base.den));
189  } else {
190  avio_wl32(pb, 0);
191  }
192  avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */
193  avio_wl32(pb, 0); /* padding */
194  if (!pb->seekable)
195  avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */
196  else
198  avi->frames_hdr_all = avio_tell(pb); /* remember this offset to fill later */
199  avio_wl32(pb, nb_frames); /* nb frames, filled later */
200  avio_wl32(pb, 0); /* initial frame */
201  avio_wl32(pb, s->nb_streams); /* nb streams */
202  avio_wl32(pb, 1024 * 1024); /* suggested buffer size */
203  if(video_enc){
204  avio_wl32(pb, video_enc->width);
205  avio_wl32(pb, video_enc->height);
206  } else {
207  avio_wl32(pb, 0);
208  avio_wl32(pb, 0);
209  }
210  avio_wl32(pb, 0); /* reserved */
211  avio_wl32(pb, 0); /* reserved */
212  avio_wl32(pb, 0); /* reserved */
213  avio_wl32(pb, 0); /* reserved */
214 
215  /* stream list */
216  for(i=0;i<n;i++) {
217  AVIStream *avist= s->streams[i]->priv_data;
218  list2 = ff_start_tag(pb, "LIST");
219  ffio_wfourcc(pb, "strl");
220 
221  stream = s->streams[i]->codec;
222 
223  /* stream generic header */
224  strh = ff_start_tag(pb, "strh");
225  switch(stream->codec_type) {
227  // XSUB subtitles behave like video tracks, other subtitles
228  // are not (yet) supported.
229  if (stream->codec_id != AV_CODEC_ID_XSUB) {
230  av_log(s, AV_LOG_ERROR, "Subtitle streams other than DivX XSUB are not supported by the AVI muxer.\n");
231  return AVERROR_PATCHWELCOME;
232  }
233  case AVMEDIA_TYPE_VIDEO: ffio_wfourcc(pb, "vids"); break;
234  case AVMEDIA_TYPE_AUDIO: ffio_wfourcc(pb, "auds"); break;
235 // case AVMEDIA_TYPE_TEXT : ffio_wfourcc(pb, "txts"); break;
236  case AVMEDIA_TYPE_DATA : ffio_wfourcc(pb, "dats"); break;
237  }
238  if(stream->codec_type == AVMEDIA_TYPE_VIDEO ||
239  stream->codec_id == AV_CODEC_ID_XSUB)
240  avio_wl32(pb, stream->codec_tag);
241  else
242  avio_wl32(pb, 1);
243  avio_wl32(pb, 0); /* flags */
244  avio_wl16(pb, 0); /* priority */
245  avio_wl16(pb, 0); /* language */
246  avio_wl32(pb, 0); /* initial frame */
247 
248  ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
249 
250  if ( stream->codec_type == AVMEDIA_TYPE_VIDEO
251  && stream->codec_id != AV_CODEC_ID_XSUB
252  && au_byterate > 1000LL*au_scale) {
253  au_byterate = 600;
254  au_scale = 1;
255  }
256  avpriv_set_pts_info(s->streams[i], 64, au_scale, au_byterate);
257  if(stream->codec_id == AV_CODEC_ID_XSUB)
258  au_scale = au_byterate = 0;
259 
260  avio_wl32(pb, au_scale); /* scale */
261  avio_wl32(pb, au_byterate); /* rate */
262 
263  avio_wl32(pb, 0); /* start */
264  avist->frames_hdr_strm = avio_tell(pb); /* remember this offset to fill later */
265  if (!pb->seekable)
266  avio_wl32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */
267  else
268  avio_wl32(pb, 0); /* length, XXX: filled later */
269 
270  /* suggested buffer size */ //FIXME set at the end to largest chunk
271  if(stream->codec_type == AVMEDIA_TYPE_VIDEO)
272  avio_wl32(pb, 1024 * 1024);
273  else if(stream->codec_type == AVMEDIA_TYPE_AUDIO)
274  avio_wl32(pb, 12 * 1024);
275  else
276  avio_wl32(pb, 0);
277  avio_wl32(pb, -1); /* quality */
278  avio_wl32(pb, au_ssize); /* sample size */
279  avio_wl32(pb, 0);
280  avio_wl16(pb, stream->width);
281  avio_wl16(pb, stream->height);
282  ff_end_tag(pb, strh);
283 
284  if(stream->codec_type != AVMEDIA_TYPE_DATA){
285  int ret;
286 
287  strf = ff_start_tag(pb, "strf");
288  switch(stream->codec_type) {
290  // XSUB subtitles behave like video tracks, other subtitles
291  // are not (yet) supported.
292  if (stream->codec_id != AV_CODEC_ID_XSUB) break;
293  case AVMEDIA_TYPE_VIDEO:
294  ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0, 0);
295  break;
296  case AVMEDIA_TYPE_AUDIO:
297  if ((ret = ff_put_wav_header(pb, stream)) < 0) {
298  return ret;
299  }
300  break;
301  default:
302  av_log(s, AV_LOG_ERROR,
303  "Invalid or not supported codec type '%s' found in the input\n",
304  (char *)av_x_if_null(av_get_media_type_string(stream->codec_type), "?"));
305  return AVERROR(EINVAL);
306  }
307  ff_end_tag(pb, strf);
308  if ((t = av_dict_get(s->streams[i]->metadata, "title", NULL, 0))) {
309  ff_riff_write_info_tag(s->pb, "strn", t->value);
310  t = NULL;
311  }
312  }
313 
314  if (pb->seekable) {
315  unsigned char tag[5];
316  int j;
317 
318  /* Starting to lay out AVI OpenDML master index.
319  * We want to make it JUNK entry for now, since we'd
320  * like to get away without making AVI an OpenDML one
321  * for compatibility reasons.
322  */
323  avist->indexes.entry = avist->indexes.ents_allocated = 0;
324  avist->indexes.indx_start = ff_start_tag(pb, "JUNK");
325  avio_wl16(pb, 4); /* wLongsPerEntry */
326  avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */
327  avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */
328  avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */
329  ffio_wfourcc(pb, avi_stream2fourcc(tag, i, stream->codec_type));
330  /* dwChunkId */
331  avio_wl64(pb, 0); /* dwReserved[3]
332  avio_wl32(pb, 0); Must be 0. */
333  for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
334  avio_wl64(pb, 0);
335  ff_end_tag(pb, avist->indexes.indx_start);
336  }
337 
338  if( stream->codec_type == AVMEDIA_TYPE_VIDEO
339  && s->streams[i]->sample_aspect_ratio.num>0
340  && s->streams[i]->sample_aspect_ratio.den>0){
341  int vprp= ff_start_tag(pb, "vprp");
343  (AVRational){stream->width, stream->height});
344  int num, den;
345  av_reduce(&num, &den, dar.num, dar.den, 0xFFFF);
346 
347  avio_wl32(pb, 0); //video format = unknown
348  avio_wl32(pb, 0); //video standard= unknown
349  avio_wl32(pb, lrintf(1.0/av_q2d(stream->time_base)));
350  avio_wl32(pb, stream->width );
351  avio_wl32(pb, stream->height);
352  avio_wl16(pb, den);
353  avio_wl16(pb, num);
354  avio_wl32(pb, stream->width );
355  avio_wl32(pb, stream->height);
356  avio_wl32(pb, 1); //progressive FIXME
357 
358  avio_wl32(pb, stream->height);
359  avio_wl32(pb, stream->width );
360  avio_wl32(pb, stream->height);
361  avio_wl32(pb, stream->width );
362  avio_wl32(pb, 0);
363  avio_wl32(pb, 0);
364 
365  avio_wl32(pb, 0);
366  avio_wl32(pb, 0);
367  ff_end_tag(pb, vprp);
368  }
369 
370  ff_end_tag(pb, list2);
371  }
372 
373  if (pb->seekable) {
374  /* AVI could become an OpenDML one, if it grows beyond 2Gb range */
375  avi->odml_list = ff_start_tag(pb, "JUNK");
376  ffio_wfourcc(pb, "odml");
377  ffio_wfourcc(pb, "dmlh");
378  avio_wl32(pb, 248);
379  for (i = 0; i < 248; i+= 4)
380  avio_wl32(pb, 0);
381  ff_end_tag(pb, avi->odml_list);
382  }
383 
384  ff_end_tag(pb, list1);
385 
387 
388  /* some padding for easier tag editing */
389  list2 = ff_start_tag(pb, "JUNK");
390  for (i = 0; i < 1016; i += 4)
391  avio_wl32(pb, 0);
392  ff_end_tag(pb, list2);
393 
394  avi->movi_list = ff_start_tag(pb, "LIST");
395  ffio_wfourcc(pb, "movi");
396 
397  avio_flush(pb);
398 
399  return 0;
400 }
401 
403 {
404  AVIOContext *pb = s->pb;
405  AVIContext *avi = s->priv_data;
406  char tag[5];
407  char ix_tag[] = "ix00";
408  int i, j;
409 
410  av_assert0(pb->seekable);
411 
412  if (avi->riff_id > AVI_MASTER_INDEX_SIZE) {
413  av_log(s, AV_LOG_ERROR, "Invalid riff index %d > %d\n",
415  return AVERROR(EINVAL);
416  }
417 
418  for (i=0;i<s->nb_streams;i++) {
419  AVIStream *avist= s->streams[i]->priv_data;
420  int64_t ix, pos;
421 
422  avi_stream2fourcc(tag, i, s->streams[i]->codec->codec_type);
423  ix_tag[3] = '0' + i;
424 
425  /* Writing AVI OpenDML leaf index chunk */
426  ix = avio_tell(pb);
427  ffio_wfourcc(pb, ix_tag); /* ix?? */
428  avio_wl32(pb, avist->indexes.entry * 8 + 24);
429  /* chunk size */
430  avio_wl16(pb, 2); /* wLongsPerEntry */
431  avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */
432  avio_w8(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */
433  avio_wl32(pb, avist->indexes.entry);
434  /* nEntriesInUse */
435  ffio_wfourcc(pb, tag); /* dwChunkId */
436  avio_wl64(pb, avi->movi_list);/* qwBaseOffset */
437  avio_wl32(pb, 0); /* dwReserved_3 (must be 0) */
438 
439  for (j=0; j<avist->indexes.entry; j++) {
440  AVIIentry* ie = avi_get_ientry(&avist->indexes, j);
441  avio_wl32(pb, ie->pos + 8);
442  avio_wl32(pb, ((uint32_t)ie->len & ~0x80000000) |
443  (ie->flags & 0x10 ? 0 : 0x80000000));
444  }
445  avio_flush(pb);
446  pos = avio_tell(pb);
447 
448  /* Updating one entry in the AVI OpenDML master index */
449  avio_seek(pb, avist->indexes.indx_start - 8, SEEK_SET);
450  ffio_wfourcc(pb, "indx"); /* enabling this entry */
451  avio_skip(pb, 8);
452  avio_wl32(pb, avi->riff_id); /* nEntriesInUse */
453  avio_skip(pb, 16*avi->riff_id);
454  avio_wl64(pb, ix); /* qwOffset */
455  avio_wl32(pb, pos - ix); /* dwSize */
456  avio_wl32(pb, avist->indexes.entry); /* dwDuration */
457 
458  avio_seek(pb, pos, SEEK_SET);
459  }
460  return 0;
461 }
462 
464 {
465  AVIOContext *pb = s->pb;
466  AVIContext *avi = s->priv_data;
467  int64_t idx_chunk;
468  int i;
469  char tag[5];
470 
471  if (pb->seekable) {
472  AVIStream *avist;
473  AVIIentry* ie = 0, *tie;
474  int empty, stream_id = -1;
475 
476  idx_chunk = ff_start_tag(pb, "idx1");
477  for(i=0; i<s->nb_streams; i++){
478  avist= s->streams[i]->priv_data;
479  avist->entry=0;
480  }
481 
482  do {
483  empty = 1;
484  for (i=0; i<s->nb_streams; i++) {
485  avist= s->streams[i]->priv_data;
486  if (avist->indexes.entry <= avist->entry)
487  continue;
488 
489  tie = avi_get_ientry(&avist->indexes, avist->entry);
490  if (empty || tie->pos < ie->pos) {
491  ie = tie;
492  stream_id = i;
493  }
494  empty = 0;
495  }
496  if (!empty) {
497  avist= s->streams[stream_id]->priv_data;
498  avi_stream2fourcc(tag, stream_id,
499  s->streams[stream_id]->codec->codec_type);
500  ffio_wfourcc(pb, tag);
501  avio_wl32(pb, ie->flags);
502  avio_wl32(pb, ie->pos);
503  avio_wl32(pb, ie->len);
504  avist->entry++;
505  }
506  } while (!empty);
507  ff_end_tag(pb, idx_chunk);
508 
509  avi_write_counters(s, avi->riff_id);
510  }
511  return 0;
512 }
513 
515 {
516  AVIContext *avi = s->priv_data;
517  AVIOContext *pb = s->pb;
518  unsigned char tag[5];
519  unsigned int flags=0;
520  const int stream_index= pkt->stream_index;
521  AVIStream *avist= s->streams[stream_index]->priv_data;
522  AVCodecContext *enc= s->streams[stream_index]->codec;
523  int size= pkt->size;
524 
525  av_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(pkt->dts), avist->packet_count, stream_index);
526  while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avist->packet_count && enc->codec_id != AV_CODEC_ID_XSUB && avist->packet_count){
527  AVPacket empty_packet;
528 
529  if(pkt->dts - avist->packet_count > 60000){
530  av_log(s, AV_LOG_ERROR, "Too large number of skipped frames %"PRId64" > 60000\n", pkt->dts - avist->packet_count);
531  return AVERROR(EINVAL);
532  }
533 
534  av_init_packet(&empty_packet);
535  empty_packet.size= 0;
536  empty_packet.data= NULL;
537  empty_packet.stream_index= stream_index;
538  avi_write_packet(s, &empty_packet);
539  av_dlog(s, "dup dts:%s packet_count:%d\n", av_ts2str(pkt->dts), avist->packet_count);
540  }
541  avist->packet_count++;
542 
543  // Make sure to put an OpenDML chunk when the file size exceeds the limits
544  if (pb->seekable &&
545  (avio_tell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) {
546 
547  avi_write_ix(s);
548  ff_end_tag(pb, avi->movi_list);
549 
550  if (avi->riff_id == 1)
551  avi_write_idx1(s);
552 
553  ff_end_tag(pb, avi->riff_start);
554  avi->movi_list = avi_start_new_riff(s, pb, "AVIX", "movi");
555  }
556 
557  avi_stream2fourcc(tag, stream_index, enc->codec_type);
558  if(pkt->flags&AV_PKT_FLAG_KEY)
559  flags = 0x10;
560  if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
561  avist->audio_strm_length += size;
562  }
563 
564  if (s->pb->seekable) {
565  AVIIndex* idx = &avist->indexes;
566  int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE;
567  int id = idx->entry % AVI_INDEX_CLUSTER_SIZE;
568  if (idx->ents_allocated <= idx->entry) {
569  idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1);
570  if (!idx->cluster) {
571  idx->ents_allocated = 0;
572  idx->entry = 0;
573  return AVERROR(ENOMEM);
574  }
576  if (!idx->cluster[cl])
577  return AVERROR(ENOMEM);
579  }
580 
581  idx->cluster[cl][id].flags = flags;
582  idx->cluster[cl][id].pos = avio_tell(pb) - avi->movi_list;
583  idx->cluster[cl][id].len = size;
584  idx->entry++;
585  }
586 
587  avio_write(pb, tag, 4);
588  avio_wl32(pb, size);
589  avio_write(pb, pkt->data, size);
590  if (size & 1)
591  avio_w8(pb, 0);
592 
593  return 0;
594 }
595 
597 {
598  AVIContext *avi = s->priv_data;
599  AVIOContext *pb = s->pb;
600  int res = 0;
601  int i, j, n, nb_frames;
602  int64_t file_size;
603 
604  if (pb->seekable){
605  if (avi->riff_id == 1) {
606  ff_end_tag(pb, avi->movi_list);
607  res = avi_write_idx1(s);
608  ff_end_tag(pb, avi->riff_start);
609  } else {
610  avi_write_ix(s);
611  ff_end_tag(pb, avi->movi_list);
612  ff_end_tag(pb, avi->riff_start);
613 
614  file_size = avio_tell(pb);
615  avio_seek(pb, avi->odml_list - 8, SEEK_SET);
616  ffio_wfourcc(pb, "LIST"); /* Making this AVI OpenDML one */
617  avio_skip(pb, 16);
618 
619  for (n=nb_frames=0;n<s->nb_streams;n++) {
620  AVCodecContext *stream = s->streams[n]->codec;
621  AVIStream *avist= s->streams[n]->priv_data;
622 
623  if (stream->codec_type == AVMEDIA_TYPE_VIDEO) {
624  if (nb_frames < avist->packet_count)
625  nb_frames = avist->packet_count;
626  } else {
627  if (stream->codec_id == AV_CODEC_ID_MP2 || stream->codec_id == AV_CODEC_ID_MP3) {
628  nb_frames += avist->packet_count;
629  }
630  }
631  }
632  avio_wl32(pb, nb_frames);
633  avio_seek(pb, file_size, SEEK_SET);
634 
635  avi_write_counters(s, avi->riff_id);
636  }
637  }
638 
639  for (i=0; i<s->nb_streams; i++) {
640  AVIStream *avist= s->streams[i]->priv_data;
641  for (j=0; j<avist->indexes.ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++)
642  av_freep(&avist->indexes.cluster[j]);
643  av_freep(&avist->indexes.cluster);
644  avist->indexes.ents_allocated = avist->indexes.entry = 0;
645  }
646 
647  return res;
648 }
649 
651  .name = "avi",
652  .long_name = NULL_IF_CONFIG_SMALL("AVI (Audio Video Interleaved)"),
653  .mime_type = "video/x-msvideo",
654  .extensions = "avi",
655  .priv_data_size = sizeof(AVIContext),
656  .audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_AC3,
657  .video_codec = AV_CODEC_ID_MPEG4,
661  .codec_tag = (const AVCodecTag* const []){
663  },
664  .flags = AVFMT_VARIABLE_FPS,
665 };