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"
38 extern char *info_name
;
39 extern char *info_artist
;
40 extern char *info_genre
;
41 extern char *info_subject
;
42 extern char *info_copyright
;
43 extern char *info_sourceform
;
44 extern char *info_comment
;
46 /* #define ODML_CHUNKLEN 0x02000000 */ /* for testing purposes */
47 #define ODML_CHUNKLEN 0x40000000
48 #define ODML_NOTKEYFRAME 0x80000000U
49 #define MOVIALIGN 0x00001000
51 float avi_aspect_override
= -1.0;
54 struct avi_odmlidx_entry
{
60 struct avi_odmlsuperidx_entry
{
66 struct avi_stream_info
{
74 struct avi_odmlidx_entry
*idx
;
75 struct avi_odmlsuperidx_entry
*superidx
;
78 static unsigned int avi_aspect(muxer_stream_t
*vstream
)
81 float aspect
= vstream
->aspect
;
83 if (avi_aspect_override
> 0.0) {
84 aspect
= avi_aspect_override
;
87 if (aspect
<= 0.0) return 0;
89 if (aspect
> 15.99/9.0 && aspect
< 16.01/9.0) {
90 return MAKE_AVI_ASPECT(16, 9);
92 if (aspect
> 3.99/3.0 && aspect
< 4.01/3.0) {
93 return MAKE_AVI_ASPECT(4, 3);
98 y
= (float)x
/ aspect
;
101 x
= (float)y
* aspect
;
104 return MAKE_AVI_ASPECT(x
, y
);
107 static muxer_stream_t
* avifile_new_stream(muxer_t
*muxer
,int type
){
108 struct avi_stream_info
*si
;
110 if (!muxer
) return NULL
;
111 if(muxer
->avih
.dwStreams
>=MUXER_MAX_STREAMS
){
112 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Too many streams! increase MUXER_MAX_STREAMS !\n");
115 s
=malloc(sizeof(muxer_stream_t
));
116 memset(s
,0,sizeof(muxer_stream_t
));
117 if(!s
) return NULL
; // no mem!?
118 muxer
->streams
[muxer
->avih
.dwStreams
]=s
;
120 s
->id
=muxer
->avih
.dwStreams
;
124 s
->priv
=si
=malloc(sizeof(struct avi_stream_info
));
125 memset(si
,0,sizeof(struct avi_stream_info
));
127 si
->idx
=calloc(si
->idxsize
, sizeof(struct avi_odmlidx_entry
));
129 si
->riffofs
=calloc((si
->riffofssize
+1), sizeof(off_t
));
130 memset(si
->riffofs
, 0, sizeof(off_t
)*si
->riffofssize
);
133 case MUXER_TYPE_VIDEO
:
134 s
->ckid
=mmioFOURCC(('0'+s
->id
/10),('0'+(s
->id
%10)),'d','c');
135 s
->h
.fccType
=streamtypeVIDEO
;
136 if(!muxer
->def_v
) muxer
->def_v
=s
;
138 case MUXER_TYPE_AUDIO
:
139 s
->ckid
=mmioFOURCC(('0'+s
->id
/10),('0'+(s
->id
%10)),'w','b');
140 s
->h
.fccType
=streamtypeAUDIO
;
143 mp_msg(MSGT_MUXER
, MSGL_WARN
, "Warning! unknown stream type: %d\n",type
);
146 muxer
->avih
.dwStreams
++;
150 static void write_avi_chunk(stream_t
*stream
,unsigned int id
,int len
,void* data
){
151 int le_len
= le2me_32(len
);
152 int le_id
= le2me_32(id
);
153 stream_write_buffer(stream
, &le_id
, 4);
154 stream_write_buffer(stream
, &le_len
, 4);
159 stream_write_buffer(stream
, data
, len
);
160 if(len
&1){ // padding
161 unsigned char zerobyte
=0;
162 stream_write_buffer(stream
, &zerobyte
, 1);
166 char *avi_junk_data
="[= MPlayer junk data! =]";
167 if(len
&1) ++len
; // padding
169 int l
=strlen(avi_junk_data
);
171 stream_write_buffer(stream
, avi_junk_data
, l
);
178 static void write_avi_list(stream_t
*s
,unsigned int id
,int len
);
179 static void avifile_write_standard_index(muxer_t
*muxer
);
181 static void avifile_odml_new_riff(muxer_t
*muxer
)
183 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
186 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: Starting new RIFF chunk at %dMB.\n", (int)(muxer
->file_end
/1024/1024));
189 if (vsi
->riffofspos
>=vsi
->riffofssize
) {
190 vsi
->riffofssize
+=16;
191 vsi
->riffofs
=realloc_struct(vsi
->riffofs
,(vsi
->riffofssize
+1),sizeof(off_t
));
193 vsi
->riffofs
[vsi
->riffofspos
] = stream_tell(muxer
->stream
);
195 /* RIFF/AVIX chunk */
196 riff
[0]=le2me_32(mmioFOURCC('R','I','F','F'));
198 riff
[2]=le2me_32(mmioFOURCC('A','V','I','X'));
199 stream_write_buffer(muxer
->stream
, riff
, 12);
201 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,0);
203 muxer
->file_end
= stream_tell(muxer
->stream
);
206 static void avifile_write_header(muxer_t
*muxer
);
208 static void avifile_write_chunk(muxer_stream_t
*s
,size_t len
,unsigned int flags
, double dts
, double pts
){
210 muxer_t
*muxer
=s
->muxer
;
211 struct avi_stream_info
*si
= s
->priv
;
212 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
213 int paddedlen
= len
+ (len
&1);
215 if (s
->type
== MUXER_TYPE_VIDEO
&& !s
->h
.dwSuggestedBufferSize
) {
216 off_t pos
=stream_tell(muxer
->stream
);
217 stream_seek(muxer
->stream
, 0);
218 avifile_write_header(muxer
);
219 stream_seek(muxer
->stream
, pos
);
222 rifflen
= muxer
->file_end
- vsi
->riffofs
[vsi
->riffofspos
] - 8;
223 if (vsi
->riffofspos
== 0) {
224 rifflen
+= 8+muxer
->idx_pos
*sizeof(AVIINDEXENTRY
);
226 if (rifflen
+ paddedlen
> ODML_CHUNKLEN
&& write_odml
== 1) {
227 if (vsi
->riffofspos
== 0) {
228 avifile_write_standard_index(muxer
);
230 avifile_odml_new_riff(muxer
);
233 if (vsi
->riffofspos
== 0) {
234 // add to the traditional index:
235 if(muxer
->idx_pos
>=muxer
->idx_size
){
236 muxer
->idx_size
+=256; // 4kB
237 muxer
->idx
=realloc_struct(muxer
->idx
,muxer
->idx_size
,16);
239 muxer
->idx
[muxer
->idx_pos
].ckid
=s
->ckid
;
240 muxer
->idx
[muxer
->idx_pos
].dwFlags
=flags
; // keyframe?
241 muxer
->idx
[muxer
->idx_pos
].dwChunkOffset
=muxer
->file_end
-(muxer
->movi_start
-4);
242 muxer
->idx
[muxer
->idx_pos
].dwChunkLength
=len
;
247 if(si
->idxpos
>=si
->idxsize
){
249 si
->idx
=realloc_struct(si
->idx
,si
->idxsize
,sizeof(*si
->idx
));
251 si
->idx
[si
->idxpos
].flags
=(flags
&AVIIF_KEYFRAME
)?0:ODML_NOTKEYFRAME
;
252 si
->idx
[si
->idxpos
].ofs
=muxer
->file_end
;
253 si
->idx
[si
->idxpos
].len
=len
;
256 // write out the chunk:
257 write_avi_chunk(muxer
->stream
,s
->ckid
,len
,s
->buffer
); /* unsigned char */
259 if (len
> s
->h
.dwSuggestedBufferSize
){
260 s
->h
.dwSuggestedBufferSize
= len
;
262 if((unsigned int)len
>s
->h
.dwSuggestedBufferSize
) s
->h
.dwSuggestedBufferSize
=len
;
264 muxer
->file_end
+= 8 + paddedlen
;
267 static void write_avi_list(stream_t
*stream
,unsigned int id
,int len
){
268 unsigned int list_id
=FOURCC_LIST
;
272 list_id
= le2me_32(list_id
);
273 le_len
= le2me_32(len
);
274 le_id
= le2me_32(id
);
275 stream_write_buffer(stream
, &list_id
, 4);
276 stream_write_buffer(stream
, &le_len
, 4);
277 stream_write_buffer(stream
, &le_id
, 4);
280 #define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(wf)->cbSize)
282 static void avifile_write_header(muxer_t
*muxer
){
284 unsigned int dmlh
[1];
286 unsigned int hdrsize
;
287 muxer_info_t info
[16];
288 VideoPropHeader vprp
;
289 uint32_t aspect
= avi_aspect(muxer
->def_v
);
290 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
291 int isodml
= vsi
->riffofspos
> 0;
293 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Writing header...\n");
295 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: Aspect information not (yet?) available or unspecified, not writing vprp header.\n");
297 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: vprp aspect is %d:%d.\n", aspect
>> 16, aspect
& 0xffff);
300 /* deal with stream delays */
301 for (i
= 0; muxer
->streams
[i
] && i
< MUXER_MAX_STREAMS
; ++i
) {
302 muxer_stream_t
*s
= muxer
->streams
[i
];
303 if (s
->type
== MUXER_TYPE_AUDIO
&& muxer
->audio_delay_fix
> 0.0) {
304 s
->h
.dwStart
= muxer
->audio_delay_fix
* s
->h
.dwRate
/s
->h
.dwScale
+ 0.5;
305 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Setting audio delay to %5.3fs.\n", (float)s
->h
.dwStart
* s
->h
.dwScale
/s
->h
.dwRate
);
307 if (s
->type
== MUXER_TYPE_VIDEO
&& muxer
->audio_delay_fix
< 0.0) {
308 s
->h
.dwStart
= -muxer
->audio_delay_fix
* s
->h
.dwRate
/s
->h
.dwScale
+ 0.5;
309 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Setting video delay to %5.3fs.\n", (float)s
->h
.dwStart
* s
->h
.dwScale
/s
->h
.dwRate
);
314 unsigned int rifflen
, movilen
;
317 vsi
->riffofs
[vsi
->riffofspos
+1] = muxer
->file_end
;
319 /* fixup RIFF lengths */
320 for (i
=0; i
<=vsi
->riffofspos
; i
++) {
321 rifflen
= vsi
->riffofs
[i
+1] - vsi
->riffofs
[i
] - 8;
322 movilen
= le2me_32(rifflen
- 12);
323 rifflen
= le2me_32(rifflen
);
324 stream_seek(muxer
->stream
, vsi
->riffofs
[i
]+4);
325 stream_write_buffer(muxer
->stream
,&rifflen
,4);
327 /* fixup movi length */
329 stream_seek(muxer
->stream
, vsi
->riffofs
[i
]+16);
330 stream_write_buffer(muxer
->stream
,&movilen
,4);
334 stream_seek(muxer
->stream
, 12);
337 riff
[0]=mmioFOURCC('R','I','F','F');
338 riff
[1]=muxer
->file_end
-2*sizeof(unsigned int); // filesize
339 riff
[2]=formtypeAVI
; // 'AVI '
340 riff
[0]=le2me_32(riff
[0]);
341 riff
[1]=le2me_32(riff
[1]);
342 riff
[2]=le2me_32(riff
[2]);
343 stream_write_buffer(muxer
->stream
,&riff
,12);
346 // update AVI header:
349 muxer
->avih
.dwMicroSecPerFrame
=1000000.0*muxer
->def_v
->h
.dwScale
/muxer
->def_v
->h
.dwRate
;
350 // muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME
351 // muxer->avih.dwPaddingGranularity=2; // ???
352 muxer
->avih
.dwFlags
|=AVIF_ISINTERLEAVED
|AVIF_TRUSTCKTYPE
;
353 muxer
->avih
.dwTotalFrames
=0;
354 for (i
=0; i
<muxer
->idx_pos
; i
++) {
355 if (muxer
->idx
[i
].ckid
== muxer
->def_v
->ckid
)
356 muxer
->avih
.dwTotalFrames
++;
358 // muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize;
359 muxer
->avih
.dwWidth
=muxer
->def_v
->bih
->biWidth
;
360 muxer
->avih
.dwHeight
=muxer
->def_v
->bih
->biHeight
;
364 hdrsize
=sizeof(muxer
->avih
)+8;
365 if (isodml
) hdrsize
+=sizeof(dmlh
)+20; // dmlh
366 // calc total header size:
367 for(i
=0;i
<muxer
->avih
.dwStreams
;i
++){
368 muxer_stream_t
*s
= muxer
->streams
[i
];
369 struct avi_stream_info
*si
= s
->priv
;
372 hdrsize
+=sizeof(muxer
->streams
[i
]->h
)+8; // strh
373 switch(muxer
->streams
[i
]->type
){
374 case MUXER_TYPE_VIDEO
:
375 hdrsize
+=muxer
->streams
[i
]->bih
->biSize
+8; // strf
377 hdrsize
+=8+4*(9+8*1); // vprp
380 case MUXER_TYPE_AUDIO
:
381 hdrsize
+=WFSIZE(muxer
->streams
[i
]->wf
)+8; // strf
384 if (isodml
&& si
&& si
->superidx
&& si
->superidxsize
) {
385 hdrsize
+= 32 + 16*si
->superidxsize
; //indx
388 write_avi_list(muxer
->stream
,listtypeAVIHEADER
,hdrsize
);
390 le2me_MainAVIHeader(&muxer
->avih
);
391 write_avi_chunk(muxer
->stream
,ckidAVIMAINHDR
,sizeof(muxer
->avih
),&muxer
->avih
); /* MainAVIHeader */
392 le2me_MainAVIHeader(&muxer
->avih
);
395 for(i
=0;i
<muxer
->avih
.dwStreams
;i
++){
396 muxer_stream_t
*s
= muxer
->streams
[i
];
397 struct avi_stream_info
*si
= s
->priv
;
398 unsigned int idxhdr
[8];
401 hdrsize
=sizeof(s
->h
)+8; // strh
402 if (si
&& si
->superidx
&& si
->superidxsize
) {
403 hdrsize
+= 32 + 16*si
->superidxsize
; //indx
406 case MUXER_TYPE_VIDEO
:
407 hdrsize
+=s
->bih
->biSize
+8; // strf
408 s
->h
.fccHandler
= s
->bih
->biCompression
;
409 s
->h
.rcFrame
.right
= s
->bih
->biWidth
;
410 s
->h
.rcFrame
.bottom
= s
->bih
->biHeight
;
412 // fill out vprp info
413 memset(&vprp
, 0, sizeof(vprp
));
414 vprp
.dwVerticalRefreshRate
= (s
->h
.dwRate
+s
->h
.dwScale
-1)/s
->h
.dwScale
;
415 vprp
.dwHTotalInT
= muxer
->avih
.dwWidth
;
416 vprp
.dwVTotalInLines
= muxer
->avih
.dwHeight
;
417 vprp
.dwFrameAspectRatio
= aspect
;
418 vprp
.dwFrameWidthInPixels
= muxer
->avih
.dwWidth
;
419 vprp
.dwFrameHeightInLines
= muxer
->avih
.dwHeight
;
420 vprp
.nbFieldPerFrame
= 1;
421 vprp
.FieldInfo
[0].CompressedBMHeight
= muxer
->avih
.dwHeight
;
422 vprp
.FieldInfo
[0].CompressedBMWidth
= muxer
->avih
.dwWidth
;
423 vprp
.FieldInfo
[0].ValidBMHeight
= muxer
->avih
.dwHeight
;
424 vprp
.FieldInfo
[0].ValidBMWidth
= muxer
->avih
.dwWidth
;
425 hdrsize
+=8+4*(9+8*1); // vprp
428 case MUXER_TYPE_AUDIO
:
429 hdrsize
+=WFSIZE(s
->wf
)+8; // strf
430 s
->h
.fccHandler
= s
->wf
->wFormatTag
;
434 write_avi_list(muxer
->stream
,listtypeSTREAMHEADER
,hdrsize
);
435 le2me_AVIStreamHeader(&s
->h
);
436 write_avi_chunk(muxer
->stream
,ckidSTREAMHEADER
,sizeof(s
->h
),&s
->h
); /* AVISTreamHeader */ // strh
437 le2me_AVIStreamHeader(&s
->h
);
440 case MUXER_TYPE_VIDEO
:
442 int biSize
=s
->bih
->biSize
;
443 le2me_BITMAPINFOHEADER(s
->bih
);
444 write_avi_chunk(muxer
->stream
,ckidSTREAMFORMAT
,biSize
,s
->bih
); /* BITMAPINFOHEADER */
445 le2me_BITMAPINFOHEADER(s
->bih
);
448 int fields
= vprp
.nbFieldPerFrame
;
449 le2me_VideoPropHeader(&vprp
);
450 le2me_VIDEO_FIELD_DESC(&vprp
.FieldInfo
[0]);
451 le2me_VIDEO_FIELD_DESC(&vprp
.FieldInfo
[1]);
452 write_avi_chunk(muxer
->stream
,mmioFOURCC('v','p','r','p'),
453 sizeof(VideoPropHeader
) -
454 sizeof(VIDEO_FIELD_DESC
)*(2-fields
),
455 &vprp
); /* Video Properties Header */
459 case MUXER_TYPE_AUDIO
:
461 int wfsize
= WFSIZE(s
->wf
);
462 le2me_WAVEFORMATEX(s
->wf
);
463 write_avi_chunk(muxer
->stream
,ckidSTREAMFORMAT
,wfsize
,s
->wf
); /* WAVEFORMATEX */
464 le2me_WAVEFORMATEX(s
->wf
);
468 if (isodml
&& si
&& si
->superidx
&& si
->superidxsize
) {
469 n
= si
->superidxsize
;
471 idxhdr
[0] = le2me_32(mmioFOURCC('i', 'n', 'd', 'x'));
472 idxhdr
[1] = le2me_32(24 + 16*n
);
473 idxhdr
[2] = le2me_32(0x00000004);
474 idxhdr
[3] = le2me_32(si
->superidxpos
);
475 idxhdr
[4] = le2me_32(s
->ckid
);
480 stream_write_buffer(muxer
->stream
,idxhdr
,sizeof(idxhdr
));
481 for (j
=0; j
<n
; j
++) {
482 struct avi_odmlsuperidx_entry
*entry
= &si
->superidx
[j
];
483 unsigned int data
[4];
484 data
[0] = le2me_32(entry
->ofs
);
485 data
[1] = le2me_32(entry
->ofs
>> 32);
486 data
[2] = le2me_32(entry
->len
);
487 data
[3] = le2me_32(entry
->duration
);
488 stream_write_buffer(muxer
->stream
,data
,sizeof(data
));
495 memset(dmlh
, 0, sizeof(dmlh
));
496 dmlh
[0] = le2me_32(muxer
->avih
.dwTotalFrames
);
497 write_avi_list(muxer
->stream
,mmioFOURCC('o','d','m','l'),sizeof(dmlh
)+8);
498 write_avi_chunk(muxer
->stream
,mmioFOURCC('d','m','l','h'),sizeof(dmlh
),dmlh
);
501 // ============= INFO ===============
502 // always include software info
503 info
[0].id
=mmioFOURCC('I','S','F','T'); // Software:
504 info
[0].text
="MEncoder " VERSION
;
505 // include any optional strings
508 info
[i
].id
=mmioFOURCC('I','N','A','M'); // Name:
509 info
[i
++].text
=info_name
;
511 if(info_artist
!=NULL
){
512 info
[i
].id
=mmioFOURCC('I','A','R','T'); // Artist:
513 info
[i
++].text
=info_artist
;
515 if(info_genre
!=NULL
){
516 info
[i
].id
=mmioFOURCC('I','G','N','R'); // Genre:
517 info
[i
++].text
=info_genre
;
519 if(info_subject
!=NULL
){
520 info
[i
].id
=mmioFOURCC('I','S','B','J'); // Subject:
521 info
[i
++].text
=info_subject
;
523 if(info_copyright
!=NULL
){
524 info
[i
].id
=mmioFOURCC('I','C','O','P'); // Copyright:
525 info
[i
++].text
=info_copyright
;
527 if(info_sourceform
!=NULL
){
528 info
[i
].id
=mmioFOURCC('I','S','R','F'); // Source Form:
529 info
[i
++].text
=info_sourceform
;
531 if(info_comment
!=NULL
){
532 info
[i
].id
=mmioFOURCC('I','C','M','T'); // Comment:
533 info
[i
++].text
=info_comment
;
539 for(i
=0;info
[i
].id
!=0;i
++) if(info
[i
].text
){
540 size_t sz
=strlen(info
[i
].text
)+1;
545 write_avi_list(muxer
->stream
,mmioFOURCC('I','N','F','O'),hdrsize
);
546 for(i
=0;info
[i
].id
!=0;i
++) if(info
[i
].text
){
547 write_avi_chunk(muxer
->stream
,info
[i
].id
,strlen(info
[i
].text
)+1,info
[i
].text
);
552 write_avi_chunk(muxer
->stream
,ckidAVIPADDING
,MOVIALIGN
-(stream_tell(muxer
->stream
)%MOVIALIGN
)-8,NULL
); /* junk */
555 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,muxer
->movi_end
-stream_tell(muxer
->stream
)-12);
557 if (stream_tell(muxer
->stream
) != MOVIALIGN
) {
558 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Opendml superindex is too big for reserved space!\n");
559 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
);
560 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Try increasing MOVIALIGN in libmpdemux/muxer_avi.c\n");
562 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,muxer
->movi_end
-stream_tell(muxer
->stream
)-12);
564 muxer
->movi_start
=stream_tell(muxer
->stream
);
565 if (muxer
->file_end
== 0) muxer
->file_end
= stream_tell(muxer
->stream
);
568 static void avifile_odml_write_index(muxer_t
*muxer
){
570 struct avi_stream_info
*si
;
573 for (i
=0; i
<muxer
->avih
.dwStreams
; i
++) {
574 int j
,k
,n
,idxpos
,len
,last
,entries_per_subidx
;
575 unsigned int idxhdr
[8];
576 s
= muxer
->streams
[i
];
580 * According to Avery Lee MSMP wants the subidx chunks to have the same size.
582 * So this code figures out how many entries we can put into
583 * an ix?? chunk, so that each ix?? chunk has the same size and the offsets
584 * don't overflow (Using ODML_CHUNKLEN for that is a bit more restrictive
585 * than it has to be though).
590 entries_per_subidx
= INT_MAX
;
592 off_t start
= si
->idx
[0].ofs
;
593 last
= entries_per_subidx
;
594 for (j
=0; j
<si
->idxpos
; j
++) {
595 len
= si
->idx
[j
].ofs
- start
;
596 if(len
>= ODML_CHUNKLEN
|| n
>= entries_per_subidx
) {
597 if (entries_per_subidx
> n
) {
598 entries_per_subidx
= n
;
600 start
= si
->idx
[j
].ofs
;
606 } while (last
!= entries_per_subidx
);
608 si
->superidxpos
= (si
->idxpos
+entries_per_subidx
-1) / entries_per_subidx
;
610 mp_msg(MSGT_MUXER
, MSGL_V
, "ODML: Stream %d: Using %d entries per subidx, %d entries in superidx\n",
611 i
, entries_per_subidx
, si
->superidxpos
);
613 si
->superidxsize
= si
->superidxpos
;
614 si
->superidx
= calloc(si
->superidxsize
, sizeof(*si
->superidx
));
615 memset(si
->superidx
, 0, sizeof(*si
->superidx
) * si
->superidxsize
);
618 for (j
=0; j
<si
->superidxpos
; j
++) {
619 off_t start
= si
->idx
[idxpos
].ofs
;
623 for (k
=0; k
<entries_per_subidx
&& idxpos
+k
<si
->idxpos
; k
++) {
624 duration
+= s
->h
.dwSampleSize
? si
->idx
[idxpos
+k
].len
/s
->h
.dwSampleSize
: 1;
627 idxhdr
[0] = le2me_32((s
->ckid
<< 16) | mmioFOURCC('i', 'x', 0, 0));
628 idxhdr
[1] = le2me_32(24 + 8*k
);
629 idxhdr
[2] = le2me_32(0x01000002);
630 idxhdr
[3] = le2me_32(k
);
631 idxhdr
[4] = le2me_32(s
->ckid
);
632 idxhdr
[5] = le2me_32(start
+ 8);
633 idxhdr
[6] = le2me_32((start
+ 8)>> 32);
634 idxhdr
[7] = 0; /* unused */
636 si
->superidx
[j
].len
= 32 + 8*k
;
637 si
->superidx
[j
].ofs
= stream_tell(muxer
->stream
);
638 si
->superidx
[j
].duration
= duration
;
640 stream_write_buffer(muxer
->stream
, idxhdr
,sizeof(idxhdr
));
641 for (k
=0; k
<entries_per_subidx
&& idxpos
<si
->idxpos
; k
++) {
642 unsigned int entry
[2];
643 entry
[0] = le2me_32(si
->idx
[idxpos
].ofs
- start
);
644 entry
[1] = le2me_32(si
->idx
[idxpos
].len
| si
->idx
[idxpos
].flags
);
646 stream_write_buffer(muxer
->stream
, entry
, sizeof(entry
));
650 muxer
->file_end
=stream_tell(muxer
->stream
);
653 static void avifile_write_standard_index(muxer_t
*muxer
){
655 muxer
->movi_end
=stream_tell(muxer
->stream
);
656 if(muxer
->idx
&& muxer
->idx_pos
>0){
658 // fixup index entries:
659 // for(i=0;i<muxer->idx_pos;i++) muxer->idx[i].dwChunkOffset-=muxer->movi_start-4;
660 // write index chunk:
661 for (i
=0; i
<muxer
->idx_pos
; i
++) le2me_AVIINDEXENTRY((&muxer
->idx
[i
]));
662 write_avi_chunk(muxer
->stream
,ckidAVINEWINDEX
,16*muxer
->idx_pos
,muxer
->idx
); /* AVIINDEXENTRY */
663 for (i
=0; i
<muxer
->idx_pos
; i
++) le2me_AVIINDEXENTRY((&muxer
->idx
[i
]));
664 muxer
->avih
.dwFlags
|=AVIF_HASINDEX
;
666 muxer
->file_end
=stream_tell(muxer
->stream
);
669 static void avifile_write_index(muxer_t
*muxer
){
670 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
672 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Writing index...\n");
673 if (vsi
->riffofspos
> 0){
674 avifile_odml_write_index(muxer
);
676 avifile_write_standard_index(muxer
);
680 static void avifile_fix_parameters(muxer_stream_t
*s
){
681 /* adjust audio_delay_fix according to individual stream delay */
682 if (s
->type
== MUXER_TYPE_AUDIO
)
683 s
->muxer
->audio_delay_fix
-= (float)s
->decoder_delay
* s
->h
.dwScale
/s
->h
.dwRate
;
684 if (s
->type
== MUXER_TYPE_VIDEO
)
685 s
->muxer
->audio_delay_fix
+= (float)s
->decoder_delay
* s
->h
.dwScale
/s
->h
.dwRate
;
688 int muxer_init_muxer_avi(muxer_t
*muxer
){
689 muxer
->cont_new_stream
= &avifile_new_stream
;
690 muxer
->cont_write_chunk
= &avifile_write_chunk
;
691 muxer
->cont_write_header
= &avifile_write_header
;
692 muxer
->cont_write_index
= &avifile_write_index
;
693 muxer
->fix_stream_parameters
= &avifile_fix_parameters
;