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.
28 #include "stream/stream.h"
33 #include "aviheader.h"
37 extern char *info_name
;
38 extern char *info_artist
;
39 extern char *info_genre
;
40 extern char *info_subject
;
41 extern char *info_copyright
;
42 extern char *info_sourceform
;
43 extern char *info_comment
;
45 /* #define ODML_CHUNKLEN 0x02000000 */ /* for testing purposes */
46 #define ODML_CHUNKLEN 0x40000000
47 #define ODML_NOTKEYFRAME 0x80000000U
48 #define MOVIALIGN 0x00001000
50 float avi_aspect_override
= -1.0;
53 struct avi_odmlidx_entry
{
59 struct avi_odmlsuperidx_entry
{
65 struct avi_stream_info
{
73 struct avi_odmlidx_entry
*idx
;
74 struct avi_odmlsuperidx_entry
*superidx
;
77 static unsigned int avi_aspect(muxer_stream_t
*vstream
)
80 float aspect
= vstream
->aspect
;
82 if (avi_aspect_override
> 0.0) {
83 aspect
= avi_aspect_override
;
86 if (aspect
<= 0.0) return 0;
88 if (aspect
> 15.99/9.0 && aspect
< 16.01/9.0) {
89 return MAKE_AVI_ASPECT(16, 9);
91 if (aspect
> 3.99/3.0 && aspect
< 4.01/3.0) {
92 return MAKE_AVI_ASPECT(4, 3);
97 y
= (float)x
/ aspect
;
100 x
= (float)y
* aspect
;
103 return MAKE_AVI_ASPECT(x
, y
);
106 static muxer_stream_t
* avifile_new_stream(muxer_t
*muxer
,int type
){
107 struct avi_stream_info
*si
;
109 if (!muxer
) return NULL
;
110 if(muxer
->avih
.dwStreams
>=MUXER_MAX_STREAMS
){
111 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Too many streams! increase MUXER_MAX_STREAMS !\n");
114 s
=malloc(sizeof(muxer_stream_t
));
115 memset(s
,0,sizeof(muxer_stream_t
));
116 if(!s
) return NULL
; // no mem!?
117 muxer
->streams
[muxer
->avih
.dwStreams
]=s
;
119 s
->id
=muxer
->avih
.dwStreams
;
123 s
->priv
=si
=malloc(sizeof(struct avi_stream_info
));
124 memset(si
,0,sizeof(struct avi_stream_info
));
126 si
->idx
=calloc(si
->idxsize
, sizeof(struct avi_odmlidx_entry
));
128 si
->riffofs
=calloc((si
->riffofssize
+1), sizeof(off_t
));
129 memset(si
->riffofs
, 0, sizeof(off_t
)*si
->riffofssize
);
132 case MUXER_TYPE_VIDEO
:
133 s
->ckid
=mmioFOURCC(('0'+s
->id
/10),('0'+(s
->id
%10)),'d','c');
134 s
->h
.fccType
=streamtypeVIDEO
;
135 if(!muxer
->def_v
) muxer
->def_v
=s
;
137 case MUXER_TYPE_AUDIO
:
138 s
->ckid
=mmioFOURCC(('0'+s
->id
/10),('0'+(s
->id
%10)),'w','b');
139 s
->h
.fccType
=streamtypeAUDIO
;
142 mp_msg(MSGT_MUXER
, MSGL_WARN
, "Warning! unknown stream type: %d\n",type
);
145 muxer
->avih
.dwStreams
++;
149 static void write_avi_chunk(stream_t
*stream
,unsigned int id
,int len
,void* data
){
150 int le_len
= le2me_32(len
);
151 int le_id
= le2me_32(id
);
152 stream_write_buffer(stream
, &le_id
, 4);
153 stream_write_buffer(stream
, &le_len
, 4);
158 stream_write_buffer(stream
, data
, len
);
159 if(len
&1){ // padding
160 unsigned char zerobyte
=0;
161 stream_write_buffer(stream
, &zerobyte
, 1);
165 char *avi_junk_data
="[= MPlayer junk data! =]";
166 if(len
&1) ++len
; // padding
168 int l
=strlen(avi_junk_data
);
170 stream_write_buffer(stream
, avi_junk_data
, l
);
177 static void write_avi_list(stream_t
*s
,unsigned int id
,int len
);
178 static void avifile_write_standard_index(muxer_t
*muxer
);
180 static void avifile_odml_new_riff(muxer_t
*muxer
)
182 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
185 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: Starting new RIFF chunk at %dMB.\n", (int)(muxer
->file_end
/1024/1024));
188 if (vsi
->riffofspos
>=vsi
->riffofssize
) {
189 vsi
->riffofssize
+=16;
190 vsi
->riffofs
=realloc_struct(vsi
->riffofs
,(vsi
->riffofssize
+1),sizeof(off_t
));
192 vsi
->riffofs
[vsi
->riffofspos
] = stream_tell(muxer
->stream
);
194 /* RIFF/AVIX chunk */
195 riff
[0]=le2me_32(mmioFOURCC('R','I','F','F'));
197 riff
[2]=le2me_32(mmioFOURCC('A','V','I','X'));
198 stream_write_buffer(muxer
->stream
, riff
, 12);
200 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,0);
202 muxer
->file_end
= stream_tell(muxer
->stream
);
205 static void avifile_write_header(muxer_t
*muxer
);
207 static void avifile_write_chunk(muxer_stream_t
*s
,size_t len
,unsigned int flags
, double dts
, double pts
){
209 muxer_t
*muxer
=s
->muxer
;
210 struct avi_stream_info
*si
= s
->priv
;
211 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
212 int paddedlen
= len
+ (len
&1);
214 if (s
->type
== MUXER_TYPE_VIDEO
&& !s
->h
.dwSuggestedBufferSize
) {
215 off_t pos
=stream_tell(muxer
->stream
);
216 stream_seek(muxer
->stream
, 0);
217 avifile_write_header(muxer
);
218 stream_seek(muxer
->stream
, pos
);
221 rifflen
= muxer
->file_end
- vsi
->riffofs
[vsi
->riffofspos
] - 8;
222 if (vsi
->riffofspos
== 0) {
223 rifflen
+= 8+muxer
->idx_pos
*sizeof(AVIINDEXENTRY
);
225 if (rifflen
+ paddedlen
> ODML_CHUNKLEN
&& write_odml
== 1) {
226 if (vsi
->riffofspos
== 0) {
227 avifile_write_standard_index(muxer
);
229 avifile_odml_new_riff(muxer
);
232 if (vsi
->riffofspos
== 0) {
233 // add to the traditional index:
234 if(muxer
->idx_pos
>=muxer
->idx_size
){
235 muxer
->idx_size
+=256; // 4kB
236 muxer
->idx
=realloc_struct(muxer
->idx
,muxer
->idx_size
,16);
238 muxer
->idx
[muxer
->idx_pos
].ckid
=s
->ckid
;
239 muxer
->idx
[muxer
->idx_pos
].dwFlags
=flags
; // keyframe?
240 muxer
->idx
[muxer
->idx_pos
].dwChunkOffset
=muxer
->file_end
-(muxer
->movi_start
-4);
241 muxer
->idx
[muxer
->idx_pos
].dwChunkLength
=len
;
246 if(si
->idxpos
>=si
->idxsize
){
248 si
->idx
=realloc_struct(si
->idx
,si
->idxsize
,sizeof(*si
->idx
));
250 si
->idx
[si
->idxpos
].flags
=(flags
&AVIIF_KEYFRAME
)?0:ODML_NOTKEYFRAME
;
251 si
->idx
[si
->idxpos
].ofs
=muxer
->file_end
;
252 si
->idx
[si
->idxpos
].len
=len
;
255 // write out the chunk:
256 write_avi_chunk(muxer
->stream
,s
->ckid
,len
,s
->buffer
); /* unsigned char */
258 if (len
> s
->h
.dwSuggestedBufferSize
){
259 s
->h
.dwSuggestedBufferSize
= len
;
261 if((unsigned int)len
>s
->h
.dwSuggestedBufferSize
) s
->h
.dwSuggestedBufferSize
=len
;
263 muxer
->file_end
+= 8 + paddedlen
;
266 static void write_avi_list(stream_t
*stream
,unsigned int id
,int len
){
267 unsigned int list_id
=FOURCC_LIST
;
271 list_id
= le2me_32(list_id
);
272 le_len
= le2me_32(len
);
273 le_id
= le2me_32(id
);
274 stream_write_buffer(stream
, &list_id
, 4);
275 stream_write_buffer(stream
, &le_len
, 4);
276 stream_write_buffer(stream
, &le_id
, 4);
279 #define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(wf)->cbSize)
281 static void avifile_write_header(muxer_t
*muxer
){
283 unsigned int dmlh
[1];
285 unsigned int hdrsize
;
286 muxer_info_t info
[16];
287 VideoPropHeader vprp
;
288 uint32_t aspect
= avi_aspect(muxer
->def_v
);
289 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
290 int isodml
= vsi
->riffofspos
> 0;
292 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Writing header...\n");
294 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: Aspect information not (yet?) available or unspecified, not writing vprp header.\n");
296 mp_msg(MSGT_MUXER
, MSGL_INFO
, "ODML: vprp aspect is %d:%d.\n", aspect
>> 16, aspect
& 0xffff);
299 /* deal with stream delays */
300 for (i
= 0; muxer
->streams
[i
] && i
< MUXER_MAX_STREAMS
; ++i
) {
301 muxer_stream_t
*s
= muxer
->streams
[i
];
302 if (s
->type
== MUXER_TYPE_AUDIO
&& muxer
->audio_delay_fix
> 0.0) {
303 s
->h
.dwStart
= muxer
->audio_delay_fix
* s
->h
.dwRate
/s
->h
.dwScale
+ 0.5;
304 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Setting audio delay to %5.3fs.\n", (float)s
->h
.dwStart
* s
->h
.dwScale
/s
->h
.dwRate
);
306 if (s
->type
== MUXER_TYPE_VIDEO
&& muxer
->audio_delay_fix
< 0.0) {
307 s
->h
.dwStart
= -muxer
->audio_delay_fix
* s
->h
.dwRate
/s
->h
.dwScale
+ 0.5;
308 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Setting video delay to %5.3fs.\n", (float)s
->h
.dwStart
* s
->h
.dwScale
/s
->h
.dwRate
);
313 unsigned int rifflen
, movilen
;
316 vsi
->riffofs
[vsi
->riffofspos
+1] = muxer
->file_end
;
318 /* fixup RIFF lengths */
319 for (i
=0; i
<=vsi
->riffofspos
; i
++) {
320 rifflen
= vsi
->riffofs
[i
+1] - vsi
->riffofs
[i
] - 8;
321 movilen
= le2me_32(rifflen
- 12);
322 rifflen
= le2me_32(rifflen
);
323 stream_seek(muxer
->stream
, vsi
->riffofs
[i
]+4);
324 stream_write_buffer(muxer
->stream
,&rifflen
,4);
326 /* fixup movi length */
328 stream_seek(muxer
->stream
, vsi
->riffofs
[i
]+16);
329 stream_write_buffer(muxer
->stream
,&movilen
,4);
333 stream_seek(muxer
->stream
, 12);
336 riff
[0]=mmioFOURCC('R','I','F','F');
337 riff
[1]=muxer
->file_end
-2*sizeof(unsigned int); // filesize
338 riff
[2]=formtypeAVI
; // 'AVI '
339 riff
[0]=le2me_32(riff
[0]);
340 riff
[1]=le2me_32(riff
[1]);
341 riff
[2]=le2me_32(riff
[2]);
342 stream_write_buffer(muxer
->stream
,&riff
,12);
345 // update AVI header:
348 muxer
->avih
.dwMicroSecPerFrame
=1000000.0*muxer
->def_v
->h
.dwScale
/muxer
->def_v
->h
.dwRate
;
349 // muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME
350 // muxer->avih.dwPaddingGranularity=2; // ???
351 muxer
->avih
.dwFlags
|=AVIF_ISINTERLEAVED
|AVIF_TRUSTCKTYPE
;
352 muxer
->avih
.dwTotalFrames
=0;
353 for (i
=0; i
<muxer
->idx_pos
; i
++) {
354 if (muxer
->idx
[i
].ckid
== muxer
->def_v
->ckid
)
355 muxer
->avih
.dwTotalFrames
++;
357 // muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize;
358 muxer
->avih
.dwWidth
=muxer
->def_v
->bih
->biWidth
;
359 muxer
->avih
.dwHeight
=muxer
->def_v
->bih
->biHeight
;
363 hdrsize
=sizeof(muxer
->avih
)+8;
364 if (isodml
) hdrsize
+=sizeof(dmlh
)+20; // dmlh
365 // calc total header size:
366 for(i
=0;i
<muxer
->avih
.dwStreams
;i
++){
367 muxer_stream_t
*s
= muxer
->streams
[i
];
368 struct avi_stream_info
*si
= s
->priv
;
371 hdrsize
+=sizeof(muxer
->streams
[i
]->h
)+8; // strh
372 switch(muxer
->streams
[i
]->type
){
373 case MUXER_TYPE_VIDEO
:
374 hdrsize
+=muxer
->streams
[i
]->bih
->biSize
+8; // strf
376 hdrsize
+=8+4*(9+8*1); // vprp
379 case MUXER_TYPE_AUDIO
:
380 hdrsize
+=WFSIZE(muxer
->streams
[i
]->wf
)+8; // strf
383 if (isodml
&& si
&& si
->superidx
&& si
->superidxsize
) {
384 hdrsize
+= 32 + 16*si
->superidxsize
; //indx
387 write_avi_list(muxer
->stream
,listtypeAVIHEADER
,hdrsize
);
389 le2me_MainAVIHeader(&muxer
->avih
);
390 write_avi_chunk(muxer
->stream
,ckidAVIMAINHDR
,sizeof(muxer
->avih
),&muxer
->avih
); /* MainAVIHeader */
391 le2me_MainAVIHeader(&muxer
->avih
);
394 for(i
=0;i
<muxer
->avih
.dwStreams
;i
++){
395 muxer_stream_t
*s
= muxer
->streams
[i
];
396 struct avi_stream_info
*si
= s
->priv
;
397 unsigned int idxhdr
[8];
400 hdrsize
=sizeof(s
->h
)+8; // strh
401 if (si
&& si
->superidx
&& si
->superidxsize
) {
402 hdrsize
+= 32 + 16*si
->superidxsize
; //indx
405 case MUXER_TYPE_VIDEO
:
406 hdrsize
+=s
->bih
->biSize
+8; // strf
407 s
->h
.fccHandler
= s
->bih
->biCompression
;
408 s
->h
.rcFrame
.right
= s
->bih
->biWidth
;
409 s
->h
.rcFrame
.bottom
= s
->bih
->biHeight
;
411 // fill out vprp info
412 memset(&vprp
, 0, sizeof(vprp
));
413 vprp
.dwVerticalRefreshRate
= (s
->h
.dwRate
+s
->h
.dwScale
-1)/s
->h
.dwScale
;
414 vprp
.dwHTotalInT
= muxer
->avih
.dwWidth
;
415 vprp
.dwVTotalInLines
= muxer
->avih
.dwHeight
;
416 vprp
.dwFrameAspectRatio
= aspect
;
417 vprp
.dwFrameWidthInPixels
= muxer
->avih
.dwWidth
;
418 vprp
.dwFrameHeightInLines
= muxer
->avih
.dwHeight
;
419 vprp
.nbFieldPerFrame
= 1;
420 vprp
.FieldInfo
[0].CompressedBMHeight
= muxer
->avih
.dwHeight
;
421 vprp
.FieldInfo
[0].CompressedBMWidth
= muxer
->avih
.dwWidth
;
422 vprp
.FieldInfo
[0].ValidBMHeight
= muxer
->avih
.dwHeight
;
423 vprp
.FieldInfo
[0].ValidBMWidth
= muxer
->avih
.dwWidth
;
424 hdrsize
+=8+4*(9+8*1); // vprp
427 case MUXER_TYPE_AUDIO
:
428 hdrsize
+=WFSIZE(s
->wf
)+8; // strf
429 s
->h
.fccHandler
= s
->wf
->wFormatTag
;
433 write_avi_list(muxer
->stream
,listtypeSTREAMHEADER
,hdrsize
);
434 le2me_AVIStreamHeader(&s
->h
);
435 write_avi_chunk(muxer
->stream
,ckidSTREAMHEADER
,sizeof(s
->h
),&s
->h
); /* AVISTreamHeader */ // strh
436 le2me_AVIStreamHeader(&s
->h
);
439 case MUXER_TYPE_VIDEO
:
441 int biSize
=s
->bih
->biSize
;
442 le2me_BITMAPINFOHEADER(s
->bih
);
443 write_avi_chunk(muxer
->stream
,ckidSTREAMFORMAT
,biSize
,s
->bih
); /* BITMAPINFOHEADER */
444 le2me_BITMAPINFOHEADER(s
->bih
);
447 int fields
= vprp
.nbFieldPerFrame
;
448 le2me_VideoPropHeader(&vprp
);
449 le2me_VIDEO_FIELD_DESC(&vprp
.FieldInfo
[0]);
450 le2me_VIDEO_FIELD_DESC(&vprp
.FieldInfo
[1]);
451 write_avi_chunk(muxer
->stream
,mmioFOURCC('v','p','r','p'),
452 sizeof(VideoPropHeader
) -
453 sizeof(VIDEO_FIELD_DESC
)*(2-fields
),
454 &vprp
); /* Video Properties Header */
458 case MUXER_TYPE_AUDIO
:
460 int wfsize
= WFSIZE(s
->wf
);
461 le2me_WAVEFORMATEX(s
->wf
);
462 write_avi_chunk(muxer
->stream
,ckidSTREAMFORMAT
,wfsize
,s
->wf
); /* WAVEFORMATEX */
463 le2me_WAVEFORMATEX(s
->wf
);
467 if (isodml
&& si
&& si
->superidx
&& si
->superidxsize
) {
468 n
= si
->superidxsize
;
470 idxhdr
[0] = le2me_32(mmioFOURCC('i', 'n', 'd', 'x'));
471 idxhdr
[1] = le2me_32(24 + 16*n
);
472 idxhdr
[2] = le2me_32(0x00000004);
473 idxhdr
[3] = le2me_32(si
->superidxpos
);
474 idxhdr
[4] = le2me_32(s
->ckid
);
479 stream_write_buffer(muxer
->stream
,idxhdr
,sizeof(idxhdr
));
480 for (j
=0; j
<n
; j
++) {
481 struct avi_odmlsuperidx_entry
*entry
= &si
->superidx
[j
];
482 unsigned int data
[4];
483 data
[0] = le2me_32(entry
->ofs
);
484 data
[1] = le2me_32(entry
->ofs
>> 32);
485 data
[2] = le2me_32(entry
->len
);
486 data
[3] = le2me_32(entry
->duration
);
487 stream_write_buffer(muxer
->stream
,data
,sizeof(data
));
494 memset(dmlh
, 0, sizeof(dmlh
));
495 dmlh
[0] = le2me_32(muxer
->avih
.dwTotalFrames
);
496 write_avi_list(muxer
->stream
,mmioFOURCC('o','d','m','l'),sizeof(dmlh
)+8);
497 write_avi_chunk(muxer
->stream
,mmioFOURCC('d','m','l','h'),sizeof(dmlh
),dmlh
);
500 // ============= INFO ===============
501 // always include software info
502 info
[0].id
=mmioFOURCC('I','S','F','T'); // Software:
503 info
[0].text
=mencoder_version
;
504 // include any optional strings
507 info
[i
].id
=mmioFOURCC('I','N','A','M'); // Name:
508 info
[i
++].text
=info_name
;
510 if(info_artist
!=NULL
){
511 info
[i
].id
=mmioFOURCC('I','A','R','T'); // Artist:
512 info
[i
++].text
=info_artist
;
514 if(info_genre
!=NULL
){
515 info
[i
].id
=mmioFOURCC('I','G','N','R'); // Genre:
516 info
[i
++].text
=info_genre
;
518 if(info_subject
!=NULL
){
519 info
[i
].id
=mmioFOURCC('I','S','B','J'); // Subject:
520 info
[i
++].text
=info_subject
;
522 if(info_copyright
!=NULL
){
523 info
[i
].id
=mmioFOURCC('I','C','O','P'); // Copyright:
524 info
[i
++].text
=info_copyright
;
526 if(info_sourceform
!=NULL
){
527 info
[i
].id
=mmioFOURCC('I','S','R','F'); // Source Form:
528 info
[i
++].text
=info_sourceform
;
530 if(info_comment
!=NULL
){
531 info
[i
].id
=mmioFOURCC('I','C','M','T'); // Comment:
532 info
[i
++].text
=info_comment
;
538 for(i
=0;info
[i
].id
!=0;i
++) if(info
[i
].text
){
539 size_t sz
=strlen(info
[i
].text
)+1;
544 write_avi_list(muxer
->stream
,mmioFOURCC('I','N','F','O'),hdrsize
);
545 for(i
=0;info
[i
].id
!=0;i
++) if(info
[i
].text
){
546 write_avi_chunk(muxer
->stream
,info
[i
].id
,strlen(info
[i
].text
)+1,info
[i
].text
);
551 write_avi_chunk(muxer
->stream
,ckidAVIPADDING
,MOVIALIGN
-(stream_tell(muxer
->stream
)%MOVIALIGN
)-8,NULL
); /* junk */
554 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,muxer
->movi_end
-stream_tell(muxer
->stream
)-12);
556 if (stream_tell(muxer
->stream
) != MOVIALIGN
) {
557 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Opendml superindex is too big for reserved space!\n");
558 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
);
559 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Try increasing MOVIALIGN in libmpdemux/muxer_avi.c\n");
561 write_avi_list(muxer
->stream
,listtypeAVIMOVIE
,muxer
->movi_end
-stream_tell(muxer
->stream
)-12);
563 muxer
->movi_start
=stream_tell(muxer
->stream
);
564 if (muxer
->file_end
== 0) muxer
->file_end
= stream_tell(muxer
->stream
);
567 static void avifile_odml_write_index(muxer_t
*muxer
){
569 struct avi_stream_info
*si
;
572 for (i
=0; i
<muxer
->avih
.dwStreams
; i
++) {
573 int j
,k
,n
,idxpos
,len
,last
,entries_per_subidx
;
574 unsigned int idxhdr
[8];
575 s
= muxer
->streams
[i
];
579 * According to Avery Lee MSMP wants the subidx chunks to have the same size.
581 * So this code figures out how many entries we can put into
582 * an ix?? chunk, so that each ix?? chunk has the same size and the offsets
583 * don't overflow (Using ODML_CHUNKLEN for that is a bit more restrictive
584 * than it has to be though).
589 entries_per_subidx
= INT_MAX
;
591 off_t start
= si
->idx
[0].ofs
;
592 last
= entries_per_subidx
;
593 for (j
=0; j
<si
->idxpos
; j
++) {
594 len
= si
->idx
[j
].ofs
- start
;
595 if(len
>= ODML_CHUNKLEN
|| n
>= entries_per_subidx
) {
596 if (entries_per_subidx
> n
) {
597 entries_per_subidx
= n
;
599 start
= si
->idx
[j
].ofs
;
605 } while (last
!= entries_per_subidx
);
607 si
->superidxpos
= (si
->idxpos
+entries_per_subidx
-1) / entries_per_subidx
;
609 mp_msg(MSGT_MUXER
, MSGL_V
, "ODML: Stream %d: Using %d entries per subidx, %d entries in superidx\n",
610 i
, entries_per_subidx
, si
->superidxpos
);
612 si
->superidxsize
= si
->superidxpos
;
613 si
->superidx
= calloc(si
->superidxsize
, sizeof(*si
->superidx
));
614 memset(si
->superidx
, 0, sizeof(*si
->superidx
) * si
->superidxsize
);
617 for (j
=0; j
<si
->superidxpos
; j
++) {
618 off_t start
= si
->idx
[idxpos
].ofs
;
622 for (k
=0; k
<entries_per_subidx
&& idxpos
+k
<si
->idxpos
; k
++) {
623 duration
+= s
->h
.dwSampleSize
? si
->idx
[idxpos
+k
].len
/s
->h
.dwSampleSize
: 1;
626 idxhdr
[0] = le2me_32((s
->ckid
<< 16) | mmioFOURCC('i', 'x', 0, 0));
627 idxhdr
[1] = le2me_32(24 + 8*k
);
628 idxhdr
[2] = le2me_32(0x01000002);
629 idxhdr
[3] = le2me_32(k
);
630 idxhdr
[4] = le2me_32(s
->ckid
);
631 idxhdr
[5] = le2me_32(start
+ 8);
632 idxhdr
[6] = le2me_32((start
+ 8)>> 32);
633 idxhdr
[7] = 0; /* unused */
635 si
->superidx
[j
].len
= 32 + 8*k
;
636 si
->superidx
[j
].ofs
= stream_tell(muxer
->stream
);
637 si
->superidx
[j
].duration
= duration
;
639 stream_write_buffer(muxer
->stream
, idxhdr
,sizeof(idxhdr
));
640 for (k
=0; k
<entries_per_subidx
&& idxpos
<si
->idxpos
; k
++) {
641 unsigned int entry
[2];
642 entry
[0] = le2me_32(si
->idx
[idxpos
].ofs
- start
);
643 entry
[1] = le2me_32(si
->idx
[idxpos
].len
| si
->idx
[idxpos
].flags
);
645 stream_write_buffer(muxer
->stream
, entry
, sizeof(entry
));
649 muxer
->file_end
=stream_tell(muxer
->stream
);
652 static void avifile_write_standard_index(muxer_t
*muxer
){
654 muxer
->movi_end
=stream_tell(muxer
->stream
);
655 if(muxer
->idx
&& muxer
->idx_pos
>0){
657 // fixup index entries:
658 // for(i=0;i<muxer->idx_pos;i++) muxer->idx[i].dwChunkOffset-=muxer->movi_start-4;
659 // write index chunk:
660 for (i
=0; i
<muxer
->idx_pos
; i
++) le2me_AVIINDEXENTRY((&muxer
->idx
[i
]));
661 write_avi_chunk(muxer
->stream
,ckidAVINEWINDEX
,16*muxer
->idx_pos
,muxer
->idx
); /* AVIINDEXENTRY */
662 for (i
=0; i
<muxer
->idx_pos
; i
++) le2me_AVIINDEXENTRY((&muxer
->idx
[i
]));
663 muxer
->avih
.dwFlags
|=AVIF_HASINDEX
;
665 muxer
->file_end
=stream_tell(muxer
->stream
);
668 static void avifile_write_index(muxer_t
*muxer
){
669 struct avi_stream_info
*vsi
= muxer
->def_v
->priv
;
671 mp_tmsg(MSGT_MUXER
, MSGL_INFO
, "Writing index...\n");
672 if (vsi
->riffofspos
> 0){
673 avifile_odml_write_index(muxer
);
675 avifile_write_standard_index(muxer
);
679 static void avifile_fix_parameters(muxer_stream_t
*s
){
680 /* adjust audio_delay_fix according to individual stream delay */
681 if (s
->type
== MUXER_TYPE_AUDIO
)
682 s
->muxer
->audio_delay_fix
-= (float)s
->decoder_delay
* s
->h
.dwScale
/s
->h
.dwRate
;
683 if (s
->type
== MUXER_TYPE_VIDEO
)
684 s
->muxer
->audio_delay_fix
+= (float)s
->decoder_delay
* s
->h
.dwScale
/s
->h
.dwRate
;
687 int muxer_init_muxer_avi(muxer_t
*muxer
){
688 muxer
->cont_new_stream
= &avifile_new_stream
;
689 muxer
->cont_write_chunk
= &avifile_write_chunk
;
690 muxer
->cont_write_header
= &avifile_write_header
;
691 muxer
->cont_write_index
= &avifile_write_index
;
692 muxer
->fix_stream_parameters
= &avifile_fix_parameters
;