11 #include "stream/stream.h"
16 #include "aviheader.h"
21 extern char *info_name
;
22 extern char *info_artist
;
23 extern char *info_genre
;
24 extern char *info_subject
;
25 extern char *info_copyright
;
26 extern char *info_sourceform
;
27 extern char *info_comment
;
29 /* #define ODML_CHUNKLEN 0x02000000 */ /* for testing purposes */
30 #define ODML_CHUNKLEN 0x40000000
31 #define ODML_NOTKEYFRAME 0x80000000U
32 #define MOVIALIGN 0x00001000
34 float avi_aspect_override
= -1.0;
37 struct avi_odmlidx_entry
{
43 struct avi_odmlsuperidx_entry
{
49 struct avi_stream_info
{
57 struct avi_odmlidx_entry
*idx
;
58 struct avi_odmlsuperidx_entry
*superidx
;
61 static unsigned int avi_aspect(muxer_stream_t
*vstream
)
64 float aspect
= vstream
->aspect
;
66 if (avi_aspect_override
> 0.0) {
67 aspect
= avi_aspect_override
;
70 if (aspect
<= 0.0) return 0;
72 if (aspect
> 15.99/9.0 && aspect
< 16.01/9.0) {
73 return MAKE_AVI_ASPECT(16, 9);
75 if (aspect
> 3.99/3.0 && aspect
< 4.01/3.0) {
76 return MAKE_AVI_ASPECT(4, 3);
81 y
= (float)x
/ aspect
;
84 x
= (float)y
* aspect
;
87 return MAKE_AVI_ASPECT(x
, y
);
90 static muxer_stream_t
* avifile_new_stream(muxer_t
*muxer
,int type
){
91 struct avi_stream_info
*si
;
93 if (!muxer
) return NULL
;
94 if(muxer
->avih
.dwStreams
>=MUXER_MAX_STREAMS
){
95 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Too many streams! increase MUXER_MAX_STREAMS !\n");
98 s
=malloc(sizeof(muxer_stream_t
));
99 memset(s
,0,sizeof(muxer_stream_t
));
100 if(!s
) return NULL
; // no mem!?
101 muxer
->streams
[muxer
->avih
.dwStreams
]=s
;
103 s
->id
=muxer
->avih
.dwStreams
;
107 s
->priv
=si
=malloc(sizeof(struct avi_stream_info
));
108 memset(si
,0,sizeof(struct avi_stream_info
));
110 si
->idx
=calloc(si
->idxsize
, sizeof(struct avi_odmlidx_entry
));
112 si
->riffofs
=calloc((si
->riffofssize
+1), sizeof(off_t
));
113 memset(si
->riffofs
, 0, sizeof(off_t
)*si
->riffofssize
);
116 case MUXER_TYPE_VIDEO
:
117 s
->ckid
=mmioFOURCC(('0'+s
->id
/10),('0'+(s
->id
%10)),'d','c');
118 s
->h
.fccType
=streamtypeVIDEO
;
119 if(!muxer
->def_v
) muxer
->def_v
=s
;
121 case MUXER_TYPE_AUDIO
:
122 s
->ckid
=mmioFOURCC(('0'+s
->id
/10),('0'+(s
->id
%10)),'w','b');
123 s
->h
.fccType
=streamtypeAUDIO
;
126 mp_msg(MSGT_MUXER
, MSGL_WARN
, "Warning! unknown stream type: %d\n",type
);
129 muxer
->avih
.dwStreams
++;
133 static void write_avi_chunk(stream_t
*stream
,unsigned int id
,int len
,void* data
){
134 int le_len
= le2me_32(len
);
135 int le_id
= le2me_32(id
);
136 stream_write_buffer(stream
, &le_id
, 4);
137 stream_write_buffer(stream
, &le_len
, 4);
142 stream_write_buffer(stream
, data
, len
);
143 if(len
&1){ // padding
144 unsigned char zerobyte
=0;
145 stream_write_buffer(stream
, &zerobyte
, 1);
149 char *avi_junk_data
="[= MPlayer junk data! =]";
150 if(len
&1) ++len
; // padding
152 int l
=strlen(avi_junk_data
);
154 stream_write_buffer(stream
, avi_junk_data
, l
);
161 static void write_avi_list(stream_t
*s
,unsigned int id
,int len
);
162 static void avifile_write_standard_index(muxer_t
*muxer
);
164 static void avifile_odml_new_riff(muxer_t
*muxer
)
166 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
169 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: Starting new RIFF chunk at %dMB.\n", (int)(muxer
->file_end
/1024/1024));
172 if (vsi
->riffofspos
>=vsi
->riffofssize
) {
173 vsi
->riffofssize
+=16;
174 vsi
->riffofs
=realloc_struct(vsi
->riffofs
,(vsi
->riffofssize
+1),sizeof(off_t
));
176 vsi
->riffofs
[vsi
->riffofspos
] = stream_tell(muxer
->stream
);
178 /* RIFF/AVIX chunk */
179 riff
[0]=le2me_32(mmioFOURCC('R','I','F','F'));
181 riff
[2]=le2me_32(mmioFOURCC('A','V','I','X'));
182 stream_write_buffer(muxer
->stream
, riff
, 12);
184 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,0);
186 muxer
->file_end
= stream_tell(muxer
->stream
);
189 static void avifile_write_header(muxer_t
*muxer
);
191 static void avifile_write_chunk(muxer_stream_t
*s
,size_t len
,unsigned int flags
, double dts
, double pts
){
193 muxer_t
*muxer
=s
->muxer
;
194 struct avi_stream_info
*si
= s
->priv
;
195 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
196 int paddedlen
= len
+ (len
&1);
198 if (s
->type
== MUXER_TYPE_VIDEO
&& !s
->h
.dwSuggestedBufferSize
) {
199 off_t pos
=stream_tell(muxer
->stream
);
200 stream_seek(muxer
->stream
, 0);
201 avifile_write_header(muxer
);
202 stream_seek(muxer
->stream
, pos
);
205 rifflen
= muxer
->file_end
- vsi
->riffofs
[vsi
->riffofspos
] - 8;
206 if (vsi
->riffofspos
== 0) {
207 rifflen
+= 8+muxer
->idx_pos
*sizeof(AVIINDEXENTRY
);
209 if (rifflen
+ paddedlen
> ODML_CHUNKLEN
&& write_odml
== 1) {
210 if (vsi
->riffofspos
== 0) {
211 avifile_write_standard_index(muxer
);
213 avifile_odml_new_riff(muxer
);
216 if (vsi
->riffofspos
== 0) {
217 // add to the traditional index:
218 if(muxer
->idx_pos
>=muxer
->idx_size
){
219 muxer
->idx_size
+=256; // 4kB
220 muxer
->idx
=realloc_struct(muxer
->idx
,muxer
->idx_size
,16);
222 muxer
->idx
[muxer
->idx_pos
].ckid
=s
->ckid
;
223 muxer
->idx
[muxer
->idx_pos
].dwFlags
=flags
; // keyframe?
224 muxer
->idx
[muxer
->idx_pos
].dwChunkOffset
=muxer
->file_end
-(muxer
->movi_start
-4);
225 muxer
->idx
[muxer
->idx_pos
].dwChunkLength
=len
;
230 if(si
->idxpos
>=si
->idxsize
){
232 si
->idx
=realloc_struct(si
->idx
,si
->idxsize
,sizeof(*si
->idx
));
234 si
->idx
[si
->idxpos
].flags
=(flags
&AVIIF_KEYFRAME
)?0:ODML_NOTKEYFRAME
;
235 si
->idx
[si
->idxpos
].ofs
=muxer
->file_end
;
236 si
->idx
[si
->idxpos
].len
=len
;
239 // write out the chunk:
240 write_avi_chunk(muxer
->stream
,s
->ckid
,len
,s
->buffer
); /* unsigned char */
242 if (len
> s
->h
.dwSuggestedBufferSize
){
243 s
->h
.dwSuggestedBufferSize
= len
;
245 if((unsigned int)len
>s
->h
.dwSuggestedBufferSize
) s
->h
.dwSuggestedBufferSize
=len
;
247 muxer
->file_end
+= 8 + paddedlen
;
250 static void write_avi_list(stream_t
*stream
,unsigned int id
,int len
){
251 unsigned int list_id
=FOURCC_LIST
;
255 list_id
= le2me_32(list_id
);
256 le_len
= le2me_32(len
);
257 le_id
= le2me_32(id
);
258 stream_write_buffer(stream
, &list_id
, 4);
259 stream_write_buffer(stream
, &le_len
, 4);
260 stream_write_buffer(stream
, &le_id
, 4);
263 #define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(wf)->cbSize)
265 static void avifile_write_header(muxer_t
*muxer
){
267 unsigned int dmlh
[1];
269 unsigned int hdrsize
;
270 muxer_info_t info
[16];
271 VideoPropHeader vprp
;
272 uint32_t aspect
= avi_aspect(muxer
->def_v
);
273 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
274 int isodml
= vsi
->riffofspos
> 0;
276 mp_msg(MSGT_MUXER
, MSGL_INFO
, MSGTR_WritingHeader
);
278 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: Aspect information not (yet?) available or unspecified, not writing vprp header.\n");
280 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: vprp aspect is %d:%d.\n", aspect
>> 16, aspect
& 0xffff);
283 /* deal with stream delays */
284 for (i
= 0; muxer
->streams
[i
] && i
< MUXER_MAX_STREAMS
; ++i
) {
285 muxer_stream_t
*s
= muxer
->streams
[i
];
286 if (s
->type
== MUXER_TYPE_AUDIO
&& muxer
->audio_delay_fix
> 0.0) {
287 s
->h
.dwStart
= muxer
->audio_delay_fix
* s
->h
.dwRate
/s
->h
.dwScale
+ 0.5;
288 mp_msg(MSGT_MUXER
, MSGL_INFO
, MSGTR_SettingAudioDelay
, (float)s
->h
.dwStart
* s
->h
.dwScale
/s
->h
.dwRate
);
290 if (s
->type
== MUXER_TYPE_VIDEO
&& muxer
->audio_delay_fix
< 0.0) {
291 s
->h
.dwStart
= -muxer
->audio_delay_fix
* s
->h
.dwRate
/s
->h
.dwScale
+ 0.5;
292 mp_msg(MSGT_MUXER
, MSGL_INFO
, MSGTR_SettingVideoDelay
, (float)s
->h
.dwStart
* s
->h
.dwScale
/s
->h
.dwRate
);
297 unsigned int rifflen
, movilen
;
300 vsi
->riffofs
[vsi
->riffofspos
+1] = muxer
->file_end
;
302 /* fixup RIFF lengths */
303 for (i
=0; i
<=vsi
->riffofspos
; i
++) {
304 rifflen
= vsi
->riffofs
[i
+1] - vsi
->riffofs
[i
] - 8;
305 movilen
= le2me_32(rifflen
- 12);
306 rifflen
= le2me_32(rifflen
);
307 stream_seek(muxer
->stream
, vsi
->riffofs
[i
]+4);
308 stream_write_buffer(muxer
->stream
,&rifflen
,4);
310 /* fixup movi length */
312 stream_seek(muxer
->stream
, vsi
->riffofs
[i
]+16);
313 stream_write_buffer(muxer
->stream
,&movilen
,4);
317 stream_seek(muxer
->stream
, 12);
320 riff
[0]=mmioFOURCC('R','I','F','F');
321 riff
[1]=muxer
->file_end
-2*sizeof(unsigned int); // filesize
322 riff
[2]=formtypeAVI
; // 'AVI '
323 riff
[0]=le2me_32(riff
[0]);
324 riff
[1]=le2me_32(riff
[1]);
325 riff
[2]=le2me_32(riff
[2]);
326 stream_write_buffer(muxer
->stream
,&riff
,12);
329 // update AVI header:
332 muxer
->avih
.dwMicroSecPerFrame
=1000000.0*muxer
->def_v
->h
.dwScale
/muxer
->def_v
->h
.dwRate
;
333 // muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME
334 // muxer->avih.dwPaddingGranularity=2; // ???
335 muxer
->avih
.dwFlags
|=AVIF_ISINTERLEAVED
|AVIF_TRUSTCKTYPE
;
336 muxer
->avih
.dwTotalFrames
=0;
337 for (i
=0; i
<muxer
->idx_pos
; i
++) {
338 if (muxer
->idx
[i
].ckid
== muxer
->def_v
->ckid
)
339 muxer
->avih
.dwTotalFrames
++;
341 // muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize;
342 muxer
->avih
.dwWidth
=muxer
->def_v
->bih
->biWidth
;
343 muxer
->avih
.dwHeight
=muxer
->def_v
->bih
->biHeight
;
347 hdrsize
=sizeof(muxer
->avih
)+8;
348 if (isodml
) hdrsize
+=sizeof(dmlh
)+20; // dmlh
349 // calc total header size:
350 for(i
=0;i
<muxer
->avih
.dwStreams
;i
++){
351 muxer_stream_t
*s
= muxer
->streams
[i
];
352 struct avi_stream_info
*si
= s
->priv
;
355 hdrsize
+=sizeof(muxer
->streams
[i
]->h
)+8; // strh
356 switch(muxer
->streams
[i
]->type
){
357 case MUXER_TYPE_VIDEO
:
358 hdrsize
+=muxer
->streams
[i
]->bih
->biSize
+8; // strf
360 hdrsize
+=8+4*(9+8*1); // vprp
363 case MUXER_TYPE_AUDIO
:
364 hdrsize
+=WFSIZE(muxer
->streams
[i
]->wf
)+8; // strf
367 if (isodml
&& si
&& si
->superidx
&& si
->superidxsize
) {
368 hdrsize
+= 32 + 16*si
->superidxsize
; //indx
371 write_avi_list(muxer
->stream
,listtypeAVIHEADER
,hdrsize
);
373 le2me_MainAVIHeader(&muxer
->avih
);
374 write_avi_chunk(muxer
->stream
,ckidAVIMAINHDR
,sizeof(muxer
->avih
),&muxer
->avih
); /* MainAVIHeader */
375 le2me_MainAVIHeader(&muxer
->avih
);
378 for(i
=0;i
<muxer
->avih
.dwStreams
;i
++){
379 muxer_stream_t
*s
= muxer
->streams
[i
];
380 struct avi_stream_info
*si
= s
->priv
;
381 unsigned int idxhdr
[8];
384 hdrsize
=sizeof(s
->h
)+8; // strh
385 if (si
&& si
->superidx
&& si
->superidxsize
) {
386 hdrsize
+= 32 + 16*si
->superidxsize
; //indx
389 case MUXER_TYPE_VIDEO
:
390 hdrsize
+=s
->bih
->biSize
+8; // strf
391 s
->h
.fccHandler
= s
->bih
->biCompression
;
392 s
->h
.rcFrame
.right
= s
->bih
->biWidth
;
393 s
->h
.rcFrame
.bottom
= s
->bih
->biHeight
;
395 // fill out vprp info
396 memset(&vprp
, 0, sizeof(vprp
));
397 vprp
.dwVerticalRefreshRate
= (s
->h
.dwRate
+s
->h
.dwScale
-1)/s
->h
.dwScale
;
398 vprp
.dwHTotalInT
= muxer
->avih
.dwWidth
;
399 vprp
.dwVTotalInLines
= muxer
->avih
.dwHeight
;
400 vprp
.dwFrameAspectRatio
= aspect
;
401 vprp
.dwFrameWidthInPixels
= muxer
->avih
.dwWidth
;
402 vprp
.dwFrameHeightInLines
= muxer
->avih
.dwHeight
;
403 vprp
.nbFieldPerFrame
= 1;
404 vprp
.FieldInfo
[0].CompressedBMHeight
= muxer
->avih
.dwHeight
;
405 vprp
.FieldInfo
[0].CompressedBMWidth
= muxer
->avih
.dwWidth
;
406 vprp
.FieldInfo
[0].ValidBMHeight
= muxer
->avih
.dwHeight
;
407 vprp
.FieldInfo
[0].ValidBMWidth
= muxer
->avih
.dwWidth
;
408 hdrsize
+=8+4*(9+8*1); // vprp
411 case MUXER_TYPE_AUDIO
:
412 hdrsize
+=WFSIZE(s
->wf
)+8; // strf
413 s
->h
.fccHandler
= s
->wf
->wFormatTag
;
417 write_avi_list(muxer
->stream
,listtypeSTREAMHEADER
,hdrsize
);
418 le2me_AVIStreamHeader(&s
->h
);
419 write_avi_chunk(muxer
->stream
,ckidSTREAMHEADER
,sizeof(s
->h
),&s
->h
); /* AVISTreamHeader */ // strh
420 le2me_AVIStreamHeader(&s
->h
);
423 case MUXER_TYPE_VIDEO
:
425 int biSize
=s
->bih
->biSize
;
426 le2me_BITMAPINFOHEADER(s
->bih
);
427 write_avi_chunk(muxer
->stream
,ckidSTREAMFORMAT
,biSize
,s
->bih
); /* BITMAPINFOHEADER */
428 le2me_BITMAPINFOHEADER(s
->bih
);
431 int fields
= vprp
.nbFieldPerFrame
;
432 le2me_VideoPropHeader(&vprp
);
433 le2me_VIDEO_FIELD_DESC(&vprp
.FieldInfo
[0]);
434 le2me_VIDEO_FIELD_DESC(&vprp
.FieldInfo
[1]);
435 write_avi_chunk(muxer
->stream
,mmioFOURCC('v','p','r','p'),
436 sizeof(VideoPropHeader
) -
437 sizeof(VIDEO_FIELD_DESC
)*(2-fields
),
438 &vprp
); /* Video Properties Header */
442 case MUXER_TYPE_AUDIO
:
444 int wfsize
= WFSIZE(s
->wf
);
445 le2me_WAVEFORMATEX(s
->wf
);
446 write_avi_chunk(muxer
->stream
,ckidSTREAMFORMAT
,wfsize
,s
->wf
); /* WAVEFORMATEX */
447 le2me_WAVEFORMATEX(s
->wf
);
451 if (isodml
&& si
&& si
->superidx
&& si
->superidxsize
) {
452 n
= si
->superidxsize
;
454 idxhdr
[0] = le2me_32(mmioFOURCC('i', 'n', 'd', 'x'));
455 idxhdr
[1] = le2me_32(24 + 16*n
);
456 idxhdr
[2] = le2me_32(0x00000004);
457 idxhdr
[3] = le2me_32(si
->superidxpos
);
458 idxhdr
[4] = le2me_32(s
->ckid
);
463 stream_write_buffer(muxer
->stream
,idxhdr
,sizeof(idxhdr
));
464 for (j
=0; j
<n
; j
++) {
465 struct avi_odmlsuperidx_entry
*entry
= &si
->superidx
[j
];
466 unsigned int data
[4];
467 data
[0] = le2me_32(entry
->ofs
);
468 data
[1] = le2me_32(entry
->ofs
>> 32);
469 data
[2] = le2me_32(entry
->len
);
470 data
[3] = le2me_32(entry
->duration
);
471 stream_write_buffer(muxer
->stream
,data
,sizeof(data
));
478 memset(dmlh
, 0, sizeof(dmlh
));
479 dmlh
[0] = le2me_32(muxer
->avih
.dwTotalFrames
);
480 write_avi_list(muxer
->stream
,mmioFOURCC('o','d','m','l'),sizeof(dmlh
)+8);
481 write_avi_chunk(muxer
->stream
,mmioFOURCC('d','m','l','h'),sizeof(dmlh
),dmlh
);
484 // ============= INFO ===============
485 // always include software info
486 info
[0].id
=mmioFOURCC('I','S','F','T'); // Software:
487 info
[0].text
="MEncoder " VERSION
;
488 // include any optional strings
491 info
[i
].id
=mmioFOURCC('I','N','A','M'); // Name:
492 info
[i
++].text
=info_name
;
494 if(info_artist
!=NULL
){
495 info
[i
].id
=mmioFOURCC('I','A','R','T'); // Artist:
496 info
[i
++].text
=info_artist
;
498 if(info_genre
!=NULL
){
499 info
[i
].id
=mmioFOURCC('I','G','N','R'); // Genre:
500 info
[i
++].text
=info_genre
;
502 if(info_subject
!=NULL
){
503 info
[i
].id
=mmioFOURCC('I','S','B','J'); // Subject:
504 info
[i
++].text
=info_subject
;
506 if(info_copyright
!=NULL
){
507 info
[i
].id
=mmioFOURCC('I','C','O','P'); // Copyright:
508 info
[i
++].text
=info_copyright
;
510 if(info_sourceform
!=NULL
){
511 info
[i
].id
=mmioFOURCC('I','S','R','F'); // Source Form:
512 info
[i
++].text
=info_sourceform
;
514 if(info_comment
!=NULL
){
515 info
[i
].id
=mmioFOURCC('I','C','M','T'); // Comment:
516 info
[i
++].text
=info_comment
;
522 for(i
=0;info
[i
].id
!=0;i
++) if(info
[i
].text
){
523 size_t sz
=strlen(info
[i
].text
)+1;
528 write_avi_list(muxer
->stream
,mmioFOURCC('I','N','F','O'),hdrsize
);
529 for(i
=0;info
[i
].id
!=0;i
++) if(info
[i
].text
){
530 write_avi_chunk(muxer
->stream
,info
[i
].id
,strlen(info
[i
].text
)+1,info
[i
].text
);
535 write_avi_chunk(muxer
->stream
,ckidAVIPADDING
,MOVIALIGN
-(stream_tell(muxer
->stream
)%MOVIALIGN
)-8,NULL
); /* junk */
538 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,muxer
->movi_end
-stream_tell(muxer
->stream
)-12);
540 if (stream_tell(muxer
->stream
) != MOVIALIGN
) {
541 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Opendml superindex is too big for reserved space!\n");
542 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Expected filepos %d, real filepos %ld, missing space %ld\n", MOVIALIGN
, stream_tell(muxer
->stream
), stream_tell(muxer
->stream
)-MOVIALIGN
);
543 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Try increasing MOVIALIGN in libmpdemux/muxer_avi.c\n");
545 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,muxer
->movi_end
-stream_tell(muxer
->stream
)-12);
547 muxer
->movi_start
=stream_tell(muxer
->stream
);
548 if (muxer
->file_end
== 0) muxer
->file_end
= stream_tell(muxer
->stream
);
551 static void avifile_odml_write_index(muxer_t
*muxer
){
553 struct avi_stream_info
*si
;
556 for (i
=0; i
<muxer
->avih
.dwStreams
; i
++) {
557 int j
,k
,n
,idxpos
,len
,last
,entries_per_subidx
;
558 unsigned int idxhdr
[8];
559 s
= muxer
->streams
[i
];
563 * According to Avery Lee MSMP wants the subidx chunks to have the same size.
565 * So this code figures out how many entries we can put into
566 * an ix?? chunk, so that each ix?? chunk has the same size and the offsets
567 * don't overflow (Using ODML_CHUNKLEN for that is a bit more restrictive
568 * than it has to be though).
573 entries_per_subidx
= INT_MAX
;
575 off_t start
= si
->idx
[0].ofs
;
576 last
= entries_per_subidx
;
577 for (j
=0; j
<si
->idxpos
; j
++) {
578 len
= si
->idx
[j
].ofs
- start
;
579 if(len
>= ODML_CHUNKLEN
|| n
>= entries_per_subidx
) {
580 if (entries_per_subidx
> n
) {
581 entries_per_subidx
= n
;
583 start
= si
->idx
[j
].ofs
;
589 } while (last
!= entries_per_subidx
);
591 si
->superidxpos
= (si
->idxpos
+entries_per_subidx
-1) / entries_per_subidx
;
593 mp_msg(MSGT_MUXER
, MSGL_V
, "ODML: Stream %d: Using %d entries per subidx, %d entries in superidx\n",
594 i
, entries_per_subidx
, si
->superidxpos
);
596 si
->superidxsize
= si
->superidxpos
;
597 si
->superidx
= calloc(si
->superidxsize
, sizeof(*si
->superidx
));
598 memset(si
->superidx
, 0, sizeof(*si
->superidx
) * si
->superidxsize
);
601 for (j
=0; j
<si
->superidxpos
; j
++) {
602 off_t start
= si
->idx
[idxpos
].ofs
;
606 for (k
=0; k
<entries_per_subidx
&& idxpos
+k
<si
->idxpos
; k
++) {
607 duration
+= s
->h
.dwSampleSize
? si
->idx
[idxpos
+k
].len
/s
->h
.dwSampleSize
: 1;
610 idxhdr
[0] = le2me_32((s
->ckid
<< 16) | mmioFOURCC('i', 'x', 0, 0));
611 idxhdr
[1] = le2me_32(24 + 8*k
);
612 idxhdr
[2] = le2me_32(0x01000002);
613 idxhdr
[3] = le2me_32(k
);
614 idxhdr
[4] = le2me_32(s
->ckid
);
615 idxhdr
[5] = le2me_32(start
+ 8);
616 idxhdr
[6] = le2me_32((start
+ 8)>> 32);
617 idxhdr
[7] = 0; /* unused */
619 si
->superidx
[j
].len
= 32 + 8*k
;
620 si
->superidx
[j
].ofs
= stream_tell(muxer
->stream
);
621 si
->superidx
[j
].duration
= duration
;
623 stream_write_buffer(muxer
->stream
, idxhdr
,sizeof(idxhdr
));
624 for (k
=0; k
<entries_per_subidx
&& idxpos
<si
->idxpos
; k
++) {
625 unsigned int entry
[2];
626 entry
[0] = le2me_32(si
->idx
[idxpos
].ofs
- start
);
627 entry
[1] = le2me_32(si
->idx
[idxpos
].len
| si
->idx
[idxpos
].flags
);
629 stream_write_buffer(muxer
->stream
, entry
, sizeof(entry
));
633 muxer
->file_end
=stream_tell(muxer
->stream
);
636 static void avifile_write_standard_index(muxer_t
*muxer
){
638 muxer
->movi_end
=stream_tell(muxer
->stream
);
639 if(muxer
->idx
&& muxer
->idx_pos
>0){
641 // fixup index entries:
642 // for(i=0;i<muxer->idx_pos;i++) muxer->idx[i].dwChunkOffset-=muxer->movi_start-4;
643 // write index chunk:
644 for (i
=0; i
<muxer
->idx_pos
; i
++) le2me_AVIINDEXENTRY((&muxer
->idx
[i
]));
645 write_avi_chunk(muxer
->stream
,ckidAVINEWINDEX
,16*muxer
->idx_pos
,muxer
->idx
); /* AVIINDEXENTRY */
646 for (i
=0; i
<muxer
->idx_pos
; i
++) le2me_AVIINDEXENTRY((&muxer
->idx
[i
]));
647 muxer
->avih
.dwFlags
|=AVIF_HASINDEX
;
649 muxer
->file_end
=stream_tell(muxer
->stream
);
652 static void avifile_write_index(muxer_t
*muxer
){
653 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
655 mp_msg(MSGT_MUXER
, MSGL_INFO
, MSGTR_WritingTrailer
);
656 if (vsi
->riffofspos
> 0){
657 avifile_odml_write_index(muxer
);
659 avifile_write_standard_index(muxer
);
663 static void avifile_fix_parameters(muxer_stream_t
*s
){
664 /* adjust audio_delay_fix according to individual stream delay */
665 if (s
->type
== MUXER_TYPE_AUDIO
)
666 s
->muxer
->audio_delay_fix
-= (float)s
->decoder_delay
* s
->h
.dwScale
/s
->h
.dwRate
;
667 if (s
->type
== MUXER_TYPE_VIDEO
)
668 s
->muxer
->audio_delay_fix
+= (float)s
->decoder_delay
* s
->h
.dwScale
/s
->h
.dwRate
;
671 int muxer_init_muxer_avi(muxer_t
*muxer
){
672 muxer
->cont_new_stream
= &avifile_new_stream
;
673 muxer
->cont_write_chunk
= &avifile_write_chunk
;
674 muxer
->cont_write_header
= &avifile_write_header
;
675 muxer
->cont_write_index
= &avifile_write_index
;
676 muxer
->fix_stream_parameters
= &avifile_fix_parameters
;