2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "stream/stream.h"
34 #include "aviheader.h"
39 extern char *info_name
;
40 extern char *info_artist
;
41 extern char *info_genre
;
42 extern char *info_subject
;
43 extern char *info_copyright
;
44 extern char *info_sourceform
;
45 extern char *info_comment
;
47 /* #define ODML_CHUNKLEN 0x02000000 */ /* for testing purposes */
48 #define ODML_CHUNKLEN 0x40000000
49 #define ODML_NOTKEYFRAME 0x80000000U
50 #define MOVIALIGN 0x00001000
52 float avi_aspect_override
= -1.0;
55 struct avi_odmlidx_entry
{
61 struct avi_odmlsuperidx_entry
{
67 struct avi_stream_info
{
75 struct avi_odmlidx_entry
*idx
;
76 struct avi_odmlsuperidx_entry
*superidx
;
79 static unsigned int avi_aspect(muxer_stream_t
*vstream
)
82 float aspect
= vstream
->aspect
;
84 if (avi_aspect_override
> 0.0) {
85 aspect
= avi_aspect_override
;
88 if (aspect
<= 0.0) return 0;
90 if (aspect
> 15.99/9.0 && aspect
< 16.01/9.0) {
91 return MAKE_AVI_ASPECT(16, 9);
93 if (aspect
> 3.99/3.0 && aspect
< 4.01/3.0) {
94 return MAKE_AVI_ASPECT(4, 3);
99 y
= (float)x
/ aspect
;
102 x
= (float)y
* aspect
;
105 return MAKE_AVI_ASPECT(x
, y
);
108 static muxer_stream_t
* avifile_new_stream(muxer_t
*muxer
,int type
){
109 struct avi_stream_info
*si
;
111 if (!muxer
) return NULL
;
112 if(muxer
->avih
.dwStreams
>=MUXER_MAX_STREAMS
){
113 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Too many streams! increase MUXER_MAX_STREAMS !\n");
116 s
=malloc(sizeof(muxer_stream_t
));
117 memset(s
,0,sizeof(muxer_stream_t
));
118 if(!s
) return NULL
; // no mem!?
119 muxer
->streams
[muxer
->avih
.dwStreams
]=s
;
121 s
->id
=muxer
->avih
.dwStreams
;
125 s
->priv
=si
=malloc(sizeof(struct avi_stream_info
));
126 memset(si
,0,sizeof(struct avi_stream_info
));
128 si
->idx
=calloc(si
->idxsize
, sizeof(struct avi_odmlidx_entry
));
130 si
->riffofs
=calloc((si
->riffofssize
+1), sizeof(off_t
));
131 memset(si
->riffofs
, 0, sizeof(off_t
)*si
->riffofssize
);
134 case MUXER_TYPE_VIDEO
:
135 s
->ckid
=mmioFOURCC(('0'+s
->id
/10),('0'+(s
->id
%10)),'d','c');
136 s
->h
.fccType
=streamtypeVIDEO
;
137 if(!muxer
->def_v
) muxer
->def_v
=s
;
139 case MUXER_TYPE_AUDIO
:
140 s
->ckid
=mmioFOURCC(('0'+s
->id
/10),('0'+(s
->id
%10)),'w','b');
141 s
->h
.fccType
=streamtypeAUDIO
;
144 mp_msg(MSGT_MUXER
, MSGL_WARN
, "Warning! unknown stream type: %d\n",type
);
147 muxer
->avih
.dwStreams
++;
151 static void write_avi_chunk(stream_t
*stream
,unsigned int id
,int len
,void* data
){
152 int le_len
= le2me_32(len
);
153 int le_id
= le2me_32(id
);
154 stream_write_buffer(stream
, &le_id
, 4);
155 stream_write_buffer(stream
, &le_len
, 4);
160 stream_write_buffer(stream
, data
, len
);
161 if(len
&1){ // padding
162 unsigned char zerobyte
=0;
163 stream_write_buffer(stream
, &zerobyte
, 1);
167 char *avi_junk_data
="[= MPlayer junk data! =]";
168 if(len
&1) ++len
; // padding
170 int l
=strlen(avi_junk_data
);
172 stream_write_buffer(stream
, avi_junk_data
, l
);
179 static void write_avi_list(stream_t
*s
,unsigned int id
,int len
);
180 static void avifile_write_standard_index(muxer_t
*muxer
);
182 static void avifile_odml_new_riff(muxer_t
*muxer
)
184 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
187 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: Starting new RIFF chunk at %dMB.\n", (int)(muxer
->file_end
/1024/1024));
190 if (vsi
->riffofspos
>=vsi
->riffofssize
) {
191 vsi
->riffofssize
+=16;
192 vsi
->riffofs
=realloc_struct(vsi
->riffofs
,(vsi
->riffofssize
+1),sizeof(off_t
));
194 vsi
->riffofs
[vsi
->riffofspos
] = stream_tell(muxer
->stream
);
196 /* RIFF/AVIX chunk */
197 riff
[0]=le2me_32(mmioFOURCC('R','I','F','F'));
199 riff
[2]=le2me_32(mmioFOURCC('A','V','I','X'));
200 stream_write_buffer(muxer
->stream
, riff
, 12);
202 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,0);
204 muxer
->file_end
= stream_tell(muxer
->stream
);
207 static void avifile_write_header(muxer_t
*muxer
);
209 static void avifile_write_chunk(muxer_stream_t
*s
,size_t len
,unsigned int flags
, double dts
, double pts
){
211 muxer_t
*muxer
=s
->muxer
;
212 struct avi_stream_info
*si
= s
->priv
;
213 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
214 int paddedlen
= len
+ (len
&1);
216 if (s
->type
== MUXER_TYPE_VIDEO
&& !s
->h
.dwSuggestedBufferSize
) {
217 off_t pos
=stream_tell(muxer
->stream
);
218 stream_seek(muxer
->stream
, 0);
219 avifile_write_header(muxer
);
220 stream_seek(muxer
->stream
, pos
);
223 rifflen
= muxer
->file_end
- vsi
->riffofs
[vsi
->riffofspos
] - 8;
224 if (vsi
->riffofspos
== 0) {
225 rifflen
+= 8+muxer
->idx_pos
*sizeof(AVIINDEXENTRY
);
227 if (rifflen
+ paddedlen
> ODML_CHUNKLEN
&& write_odml
== 1) {
228 if (vsi
->riffofspos
== 0) {
229 avifile_write_standard_index(muxer
);
231 avifile_odml_new_riff(muxer
);
234 if (vsi
->riffofspos
== 0) {
235 // add to the traditional index:
236 if(muxer
->idx_pos
>=muxer
->idx_size
){
237 muxer
->idx_size
+=256; // 4kB
238 muxer
->idx
=realloc_struct(muxer
->idx
,muxer
->idx_size
,16);
240 muxer
->idx
[muxer
->idx_pos
].ckid
=s
->ckid
;
241 muxer
->idx
[muxer
->idx_pos
].dwFlags
=flags
; // keyframe?
242 muxer
->idx
[muxer
->idx_pos
].dwChunkOffset
=muxer
->file_end
-(muxer
->movi_start
-4);
243 muxer
->idx
[muxer
->idx_pos
].dwChunkLength
=len
;
248 if(si
->idxpos
>=si
->idxsize
){
250 si
->idx
=realloc_struct(si
->idx
,si
->idxsize
,sizeof(*si
->idx
));
252 si
->idx
[si
->idxpos
].flags
=(flags
&AVIIF_KEYFRAME
)?0:ODML_NOTKEYFRAME
;
253 si
->idx
[si
->idxpos
].ofs
=muxer
->file_end
;
254 si
->idx
[si
->idxpos
].len
=len
;
257 // write out the chunk:
258 write_avi_chunk(muxer
->stream
,s
->ckid
,len
,s
->buffer
); /* unsigned char */
260 if (len
> s
->h
.dwSuggestedBufferSize
){
261 s
->h
.dwSuggestedBufferSize
= len
;
263 if((unsigned int)len
>s
->h
.dwSuggestedBufferSize
) s
->h
.dwSuggestedBufferSize
=len
;
265 muxer
->file_end
+= 8 + paddedlen
;
268 static void write_avi_list(stream_t
*stream
,unsigned int id
,int len
){
269 unsigned int list_id
=FOURCC_LIST
;
273 list_id
= le2me_32(list_id
);
274 le_len
= le2me_32(len
);
275 le_id
= le2me_32(id
);
276 stream_write_buffer(stream
, &list_id
, 4);
277 stream_write_buffer(stream
, &le_len
, 4);
278 stream_write_buffer(stream
, &le_id
, 4);
281 #define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(wf)->cbSize)
283 static void avifile_write_header(muxer_t
*muxer
){
285 unsigned int dmlh
[1];
287 unsigned int hdrsize
;
288 muxer_info_t info
[16];
289 VideoPropHeader vprp
;
290 uint32_t aspect
= avi_aspect(muxer
->def_v
);
291 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
292 int isodml
= vsi
->riffofspos
> 0;
294 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Writing header...\n");
296 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: Aspect information not (yet?) available or unspecified, not writing vprp header.\n");
298 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: vprp aspect is %d:%d.\n", aspect
>> 16, aspect
& 0xffff);
301 /* deal with stream delays */
302 for (i
= 0; muxer
->streams
[i
] && i
< MUXER_MAX_STREAMS
; ++i
) {
303 muxer_stream_t
*s
= muxer
->streams
[i
];
304 if (s
->type
== MUXER_TYPE_AUDIO
&& muxer
->audio_delay_fix
> 0.0) {
305 s
->h
.dwStart
= muxer
->audio_delay_fix
* s
->h
.dwRate
/s
->h
.dwScale
+ 0.5;
306 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Setting audio delay to %5.3fs.\n", (float)s
->h
.dwStart
* s
->h
.dwScale
/s
->h
.dwRate
);
308 if (s
->type
== MUXER_TYPE_VIDEO
&& muxer
->audio_delay_fix
< 0.0) {
309 s
->h
.dwStart
= -muxer
->audio_delay_fix
* s
->h
.dwRate
/s
->h
.dwScale
+ 0.5;
310 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Setting video delay to %5.3fs.\n", (float)s
->h
.dwStart
* s
->h
.dwScale
/s
->h
.dwRate
);
315 unsigned int rifflen
, movilen
;
318 vsi
->riffofs
[vsi
->riffofspos
+1] = muxer
->file_end
;
320 /* fixup RIFF lengths */
321 for (i
=0; i
<=vsi
->riffofspos
; i
++) {
322 rifflen
= vsi
->riffofs
[i
+1] - vsi
->riffofs
[i
] - 8;
323 movilen
= le2me_32(rifflen
- 12);
324 rifflen
= le2me_32(rifflen
);
325 stream_seek(muxer
->stream
, vsi
->riffofs
[i
]+4);
326 stream_write_buffer(muxer
->stream
,&rifflen
,4);
328 /* fixup movi length */
330 stream_seek(muxer
->stream
, vsi
->riffofs
[i
]+16);
331 stream_write_buffer(muxer
->stream
,&movilen
,4);
335 stream_seek(muxer
->stream
, 12);
338 riff
[0]=mmioFOURCC('R','I','F','F');
339 riff
[1]=muxer
->file_end
-2*sizeof(unsigned int); // filesize
340 riff
[2]=formtypeAVI
; // 'AVI '
341 riff
[0]=le2me_32(riff
[0]);
342 riff
[1]=le2me_32(riff
[1]);
343 riff
[2]=le2me_32(riff
[2]);
344 stream_write_buffer(muxer
->stream
,&riff
,12);
347 // update AVI header:
350 muxer
->avih
.dwMicroSecPerFrame
=1000000.0*muxer
->def_v
->h
.dwScale
/muxer
->def_v
->h
.dwRate
;
351 // muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME
352 // muxer->avih.dwPaddingGranularity=2; // ???
353 muxer
->avih
.dwFlags
|=AVIF_ISINTERLEAVED
|AVIF_TRUSTCKTYPE
;
354 muxer
->avih
.dwTotalFrames
=0;
355 for (i
=0; i
<muxer
->idx_pos
; i
++) {
356 if (muxer
->idx
[i
].ckid
== muxer
->def_v
->ckid
)
357 muxer
->avih
.dwTotalFrames
++;
359 // muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize;
360 muxer
->avih
.dwWidth
=muxer
->def_v
->bih
->biWidth
;
361 muxer
->avih
.dwHeight
=muxer
->def_v
->bih
->biHeight
;
365 hdrsize
=sizeof(muxer
->avih
)+8;
366 if (isodml
) hdrsize
+=sizeof(dmlh
)+20; // dmlh
367 // calc total header size:
368 for(i
=0;i
<muxer
->avih
.dwStreams
;i
++){
369 muxer_stream_t
*s
= muxer
->streams
[i
];
370 struct avi_stream_info
*si
= s
->priv
;
373 hdrsize
+=sizeof(muxer
->streams
[i
]->h
)+8; // strh
374 switch(muxer
->streams
[i
]->type
){
375 case MUXER_TYPE_VIDEO
:
376 hdrsize
+=muxer
->streams
[i
]->bih
->biSize
+8; // strf
378 hdrsize
+=8+4*(9+8*1); // vprp
381 case MUXER_TYPE_AUDIO
:
382 hdrsize
+=WFSIZE(muxer
->streams
[i
]->wf
)+8; // strf
385 if (isodml
&& si
&& si
->superidx
&& si
->superidxsize
) {
386 hdrsize
+= 32 + 16*si
->superidxsize
; //indx
389 write_avi_list(muxer
->stream
,listtypeAVIHEADER
,hdrsize
);
391 le2me_MainAVIHeader(&muxer
->avih
);
392 write_avi_chunk(muxer
->stream
,ckidAVIMAINHDR
,sizeof(muxer
->avih
),&muxer
->avih
); /* MainAVIHeader */
393 le2me_MainAVIHeader(&muxer
->avih
);
396 for(i
=0;i
<muxer
->avih
.dwStreams
;i
++){
397 muxer_stream_t
*s
= muxer
->streams
[i
];
398 struct avi_stream_info
*si
= s
->priv
;
399 unsigned int idxhdr
[8];
402 hdrsize
=sizeof(s
->h
)+8; // strh
403 if (si
&& si
->superidx
&& si
->superidxsize
) {
404 hdrsize
+= 32 + 16*si
->superidxsize
; //indx
407 case MUXER_TYPE_VIDEO
:
408 hdrsize
+=s
->bih
->biSize
+8; // strf
409 s
->h
.fccHandler
= s
->bih
->biCompression
;
410 s
->h
.rcFrame
.right
= s
->bih
->biWidth
;
411 s
->h
.rcFrame
.bottom
= s
->bih
->biHeight
;
413 // fill out vprp info
414 memset(&vprp
, 0, sizeof(vprp
));
415 vprp
.dwVerticalRefreshRate
= (s
->h
.dwRate
+s
->h
.dwScale
-1)/s
->h
.dwScale
;
416 vprp
.dwHTotalInT
= muxer
->avih
.dwWidth
;
417 vprp
.dwVTotalInLines
= muxer
->avih
.dwHeight
;
418 vprp
.dwFrameAspectRatio
= aspect
;
419 vprp
.dwFrameWidthInPixels
= muxer
->avih
.dwWidth
;
420 vprp
.dwFrameHeightInLines
= muxer
->avih
.dwHeight
;
421 vprp
.nbFieldPerFrame
= 1;
422 vprp
.FieldInfo
[0].CompressedBMHeight
= muxer
->avih
.dwHeight
;
423 vprp
.FieldInfo
[0].CompressedBMWidth
= muxer
->avih
.dwWidth
;
424 vprp
.FieldInfo
[0].ValidBMHeight
= muxer
->avih
.dwHeight
;
425 vprp
.FieldInfo
[0].ValidBMWidth
= muxer
->avih
.dwWidth
;
426 hdrsize
+=8+4*(9+8*1); // vprp
429 case MUXER_TYPE_AUDIO
:
430 hdrsize
+=WFSIZE(s
->wf
)+8; // strf
431 s
->h
.fccHandler
= s
->wf
->wFormatTag
;
435 write_avi_list(muxer
->stream
,listtypeSTREAMHEADER
,hdrsize
);
436 le2me_AVIStreamHeader(&s
->h
);
437 write_avi_chunk(muxer
->stream
,ckidSTREAMHEADER
,sizeof(s
->h
),&s
->h
); /* AVISTreamHeader */ // strh
438 le2me_AVIStreamHeader(&s
->h
);
441 case MUXER_TYPE_VIDEO
:
443 int biSize
=s
->bih
->biSize
;
444 le2me_BITMAPINFOHEADER(s
->bih
);
445 write_avi_chunk(muxer
->stream
,ckidSTREAMFORMAT
,biSize
,s
->bih
); /* BITMAPINFOHEADER */
446 le2me_BITMAPINFOHEADER(s
->bih
);
449 int fields
= vprp
.nbFieldPerFrame
;
450 le2me_VideoPropHeader(&vprp
);
451 le2me_VIDEO_FIELD_DESC(&vprp
.FieldInfo
[0]);
452 le2me_VIDEO_FIELD_DESC(&vprp
.FieldInfo
[1]);
453 write_avi_chunk(muxer
->stream
,mmioFOURCC('v','p','r','p'),
454 sizeof(VideoPropHeader
) -
455 sizeof(VIDEO_FIELD_DESC
)*(2-fields
),
456 &vprp
); /* Video Properties Header */
460 case MUXER_TYPE_AUDIO
:
462 int wfsize
= WFSIZE(s
->wf
);
463 le2me_WAVEFORMATEX(s
->wf
);
464 write_avi_chunk(muxer
->stream
,ckidSTREAMFORMAT
,wfsize
,s
->wf
); /* WAVEFORMATEX */
465 le2me_WAVEFORMATEX(s
->wf
);
469 if (isodml
&& si
&& si
->superidx
&& si
->superidxsize
) {
470 n
= si
->superidxsize
;
472 idxhdr
[0] = le2me_32(mmioFOURCC('i', 'n', 'd', 'x'));
473 idxhdr
[1] = le2me_32(24 + 16*n
);
474 idxhdr
[2] = le2me_32(0x00000004);
475 idxhdr
[3] = le2me_32(si
->superidxpos
);
476 idxhdr
[4] = le2me_32(s
->ckid
);
481 stream_write_buffer(muxer
->stream
,idxhdr
,sizeof(idxhdr
));
482 for (j
=0; j
<n
; j
++) {
483 struct avi_odmlsuperidx_entry
*entry
= &si
->superidx
[j
];
484 unsigned int data
[4];
485 data
[0] = le2me_32(entry
->ofs
);
486 data
[1] = le2me_32(entry
->ofs
>> 32);
487 data
[2] = le2me_32(entry
->len
);
488 data
[3] = le2me_32(entry
->duration
);
489 stream_write_buffer(muxer
->stream
,data
,sizeof(data
));
496 memset(dmlh
, 0, sizeof(dmlh
));
497 dmlh
[0] = le2me_32(muxer
->avih
.dwTotalFrames
);
498 write_avi_list(muxer
->stream
,mmioFOURCC('o','d','m','l'),sizeof(dmlh
)+8);
499 write_avi_chunk(muxer
->stream
,mmioFOURCC('d','m','l','h'),sizeof(dmlh
),dmlh
);
502 // ============= INFO ===============
503 // always include software info
504 info
[0].id
=mmioFOURCC('I','S','F','T'); // Software:
505 info
[0].text
="MEncoder " VERSION
;
506 // include any optional strings
509 info
[i
].id
=mmioFOURCC('I','N','A','M'); // Name:
510 info
[i
++].text
=info_name
;
512 if(info_artist
!=NULL
){
513 info
[i
].id
=mmioFOURCC('I','A','R','T'); // Artist:
514 info
[i
++].text
=info_artist
;
516 if(info_genre
!=NULL
){
517 info
[i
].id
=mmioFOURCC('I','G','N','R'); // Genre:
518 info
[i
++].text
=info_genre
;
520 if(info_subject
!=NULL
){
521 info
[i
].id
=mmioFOURCC('I','S','B','J'); // Subject:
522 info
[i
++].text
=info_subject
;
524 if(info_copyright
!=NULL
){
525 info
[i
].id
=mmioFOURCC('I','C','O','P'); // Copyright:
526 info
[i
++].text
=info_copyright
;
528 if(info_sourceform
!=NULL
){
529 info
[i
].id
=mmioFOURCC('I','S','R','F'); // Source Form:
530 info
[i
++].text
=info_sourceform
;
532 if(info_comment
!=NULL
){
533 info
[i
].id
=mmioFOURCC('I','C','M','T'); // Comment:
534 info
[i
++].text
=info_comment
;
540 for(i
=0;info
[i
].id
!=0;i
++) if(info
[i
].text
){
541 size_t sz
=strlen(info
[i
].text
)+1;
546 write_avi_list(muxer
->stream
,mmioFOURCC('I','N','F','O'),hdrsize
);
547 for(i
=0;info
[i
].id
!=0;i
++) if(info
[i
].text
){
548 write_avi_chunk(muxer
->stream
,info
[i
].id
,strlen(info
[i
].text
)+1,info
[i
].text
);
553 write_avi_chunk(muxer
->stream
,ckidAVIPADDING
,MOVIALIGN
-(stream_tell(muxer
->stream
)%MOVIALIGN
)-8,NULL
); /* junk */
556 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,muxer
->movi_end
-stream_tell(muxer
->stream
)-12);
558 if (stream_tell(muxer
->stream
) != MOVIALIGN
) {
559 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Opendml superindex is too big for reserved space!\n");
560 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
);
561 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Try increasing MOVIALIGN in libmpdemux/muxer_avi.c\n");
563 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,muxer
->movi_end
-stream_tell(muxer
->stream
)-12);
565 muxer
->movi_start
=stream_tell(muxer
->stream
);
566 if (muxer
->file_end
== 0) muxer
->file_end
= stream_tell(muxer
->stream
);
569 static void avifile_odml_write_index(muxer_t
*muxer
){
571 struct avi_stream_info
*si
;
574 for (i
=0; i
<muxer
->avih
.dwStreams
; i
++) {
575 int j
,k
,n
,idxpos
,len
,last
,entries_per_subidx
;
576 unsigned int idxhdr
[8];
577 s
= muxer
->streams
[i
];
581 * According to Avery Lee MSMP wants the subidx chunks to have the same size.
583 * So this code figures out how many entries we can put into
584 * an ix?? chunk, so that each ix?? chunk has the same size and the offsets
585 * don't overflow (Using ODML_CHUNKLEN for that is a bit more restrictive
586 * than it has to be though).
591 entries_per_subidx
= INT_MAX
;
593 off_t start
= si
->idx
[0].ofs
;
594 last
= entries_per_subidx
;
595 for (j
=0; j
<si
->idxpos
; j
++) {
596 len
= si
->idx
[j
].ofs
- start
;
597 if(len
>= ODML_CHUNKLEN
|| n
>= entries_per_subidx
) {
598 if (entries_per_subidx
> n
) {
599 entries_per_subidx
= n
;
601 start
= si
->idx
[j
].ofs
;
607 } while (last
!= entries_per_subidx
);
609 si
->superidxpos
= (si
->idxpos
+entries_per_subidx
-1) / entries_per_subidx
;
611 mp_msg(MSGT_MUXER
, MSGL_V
, "ODML: Stream %d: Using %d entries per subidx, %d entries in superidx\n",
612 i
, entries_per_subidx
, si
->superidxpos
);
614 si
->superidxsize
= si
->superidxpos
;
615 si
->superidx
= calloc(si
->superidxsize
, sizeof(*si
->superidx
));
616 memset(si
->superidx
, 0, sizeof(*si
->superidx
) * si
->superidxsize
);
619 for (j
=0; j
<si
->superidxpos
; j
++) {
620 off_t start
= si
->idx
[idxpos
].ofs
;
624 for (k
=0; k
<entries_per_subidx
&& idxpos
+k
<si
->idxpos
; k
++) {
625 duration
+= s
->h
.dwSampleSize
? si
->idx
[idxpos
+k
].len
/s
->h
.dwSampleSize
: 1;
628 idxhdr
[0] = le2me_32((s
->ckid
<< 16) | mmioFOURCC('i', 'x', 0, 0));
629 idxhdr
[1] = le2me_32(24 + 8*k
);
630 idxhdr
[2] = le2me_32(0x01000002);
631 idxhdr
[3] = le2me_32(k
);
632 idxhdr
[4] = le2me_32(s
->ckid
);
633 idxhdr
[5] = le2me_32(start
+ 8);
634 idxhdr
[6] = le2me_32((start
+ 8)>> 32);
635 idxhdr
[7] = 0; /* unused */
637 si
->superidx
[j
].len
= 32 + 8*k
;
638 si
->superidx
[j
].ofs
= stream_tell(muxer
->stream
);
639 si
->superidx
[j
].duration
= duration
;
641 stream_write_buffer(muxer
->stream
, idxhdr
,sizeof(idxhdr
));
642 for (k
=0; k
<entries_per_subidx
&& idxpos
<si
->idxpos
; k
++) {
643 unsigned int entry
[2];
644 entry
[0] = le2me_32(si
->idx
[idxpos
].ofs
- start
);
645 entry
[1] = le2me_32(si
->idx
[idxpos
].len
| si
->idx
[idxpos
].flags
);
647 stream_write_buffer(muxer
->stream
, entry
, sizeof(entry
));
651 muxer
->file_end
=stream_tell(muxer
->stream
);
654 static void avifile_write_standard_index(muxer_t
*muxer
){
656 muxer
->movi_end
=stream_tell(muxer
->stream
);
657 if(muxer
->idx
&& muxer
->idx_pos
>0){
659 // fixup index entries:
660 // for(i=0;i<muxer->idx_pos;i++) muxer->idx[i].dwChunkOffset-=muxer->movi_start-4;
661 // write index chunk:
662 for (i
=0; i
<muxer
->idx_pos
; i
++) le2me_AVIINDEXENTRY((&muxer
->idx
[i
]));
663 write_avi_chunk(muxer
->stream
,ckidAVINEWINDEX
,16*muxer
->idx_pos
,muxer
->idx
); /* AVIINDEXENTRY */
664 for (i
=0; i
<muxer
->idx_pos
; i
++) le2me_AVIINDEXENTRY((&muxer
->idx
[i
]));
665 muxer
->avih
.dwFlags
|=AVIF_HASINDEX
;
667 muxer
->file_end
=stream_tell(muxer
->stream
);
670 static void avifile_write_index(muxer_t
*muxer
){
671 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
673 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Writing index...\n");
674 if (vsi
->riffofspos
> 0){
675 avifile_odml_write_index(muxer
);
677 avifile_write_standard_index(muxer
);
681 static void avifile_fix_parameters(muxer_stream_t
*s
){
682 /* adjust audio_delay_fix according to individual stream delay */
683 if (s
->type
== MUXER_TYPE_AUDIO
)
684 s
->muxer
->audio_delay_fix
-= (float)s
->decoder_delay
* s
->h
.dwScale
/s
->h
.dwRate
;
685 if (s
->type
== MUXER_TYPE_VIDEO
)
686 s
->muxer
->audio_delay_fix
+= (float)s
->decoder_delay
* s
->h
.dwScale
/s
->h
.dwRate
;
689 int muxer_init_muxer_avi(muxer_t
*muxer
){
690 muxer
->cont_new_stream
= &avifile_new_stream
;
691 muxer
->cont_write_chunk
= &avifile_write_chunk
;
692 muxer
->cont_write_header
= &avifile_write_header
;
693 muxer
->cont_write_index
= &avifile_write_index
;
694 muxer
->fix_stream_parameters
= &avifile_fix_parameters
;