1
/***************************************************************************
2
oplug_avi.cpp - description
5
This set of function is here to provide a simple api to the gui
6
It will facilitate the use of other function such as audio processing
9
begin : Mon Feb 11 2002
10
copyright : (C) 2002 by mean
11
email : fixounet@free.fr
12
***************************************************************************/
15
* MODIFIED Feb 2005 by GMV: ODML write support
18
/***************************************************************************
20
* This program is free software; you can redistribute it and/or modify *
21
* it under the terms of the GNU General Public License as published by *
22
* the Free Software Foundation; either version 2 of the License, or *
23
* (at your option) any later version. *
25
***************************************************************************/
32
#include <ADM_assert.h>
40
#include "ADM_audio/aviaudio.hxx"
44
#include "op_aviwrite.hxx"
45
#include "ADM_toolkit/toolkit.hxx"
46
#include "ADM_osSupport/ADM_quota.h"
47
#include "ADM_fileio.h"
49
// MOD Feb 2005 by GMV
50
#include "ADM_osSupport/ADM_debugID.h"
51
#define MODULE_NAME MODULE_SAVE_AVI
52
#include "ADM_osSupport/ADM_debug.h"
54
// END MOD Feb 2005 by GMV
55
uint32_t ADM_UsecFromFps1000(uint32_t fps1000);
59
uint32_t fcc, flags, offset, len;
66
IdxEntry *myindex = NULL;
69
aviWrite::aviWrite( void )
77
// MOD Feb 2005 by GMV: ODML support
79
// END MOD Feb 2005 by GMV
82
// MOD Feb 2005 by GMV: remove ODML index
83
aviWrite::~aviWrite(){
101
odml_destroy_index();
103
// END MOD Feb 2005 by GMV
105
uint8_t aviWrite::sync( void )
113
// Overwrite some headers with their final value
116
uint8_t aviWrite::updateHeader (MainAVIHeader * mainheader,
117
AVIStreamHeader * videostream,
118
AVIStreamHeader * astream)
125
// Update main header
126
#ifdef ADM_BIG_ENDIAN
128
memcpy(&ma,mainheader,sizeof(MainAVIHeader));
129
Endian_AviMainHeader(&ma);
130
_file->write ((uint8_t *)&ma, sizeof (ma));
132
_file->write ((uint8_t *)mainheader, sizeof (MainAVIHeader));
134
// now update video stream header
136
#ifdef ADM_BIG_ENDIAN
139
memcpy(&as,videostream,sizeof(as));
140
Endian_AviStreamHeader(&as);
141
_file->write ((uint8_t *)&as, sizeof (as));
143
_file->write ((uint8_t *)videostream, sizeof (AVIStreamHeader));
145
// should do audio too, but i's relatively harmless...
146
// Yes, indeed it helps for VBR audio :)
151
//________________________________________________
152
// Beginning of the write process
153
// We fill-in the headers
154
// 1- Create list and write main header
155
//_______________________________________________
156
uint8_t aviWrite::writeMainHeader( void )
160
ADM_assert (LAll == NULL);
164
LAll = new AviList ("RIFF", _file);
165
LAll->Begin ("AVI ");
167
LMain = new AviList ("LIST", _file);
168
LMain->Begin ("hdrl");
169
LMain->Write32 ("avih");
170
LMain->Write32 (sizeof (MainAVIHeader));
171
#ifdef ADM_BIG_ENDIAN
173
memcpy(&ma,&_mainheader,sizeof(ma));
174
Endian_AviMainHeader(&ma);
175
LMain->Write((uint8_t *)&ma,sizeof(ma));
177
LMain->Write ((uint8_t *) &_mainheader, sizeof (MainAVIHeader));
181
//________________________________________________
182
// Beginning of the write process
183
// We fill-in the headers
184
// 2- Write video headers
185
//_______________________________________________
186
uint8_t aviWrite::writeVideoHeader( uint8_t *extra, uint32_t extraLen )
191
_videostream.fccType = fourCC::get ((uint8_t *) "vids");
192
_bih.biSize=sizeof(_bih)+extraLen;
193
// MOD Feb 2005 by GMV: video super index length
194
uint32_t odml_super_idx_size=24+odml_nbrof_index*16;
195
// END MOD Feb 2005 by GMV
196
#ifdef ADM_BIG_ENDIAN
197
// in case of Little endian, do the usual swap crap
201
memcpy(&as,&_videostream,sizeof(as));
202
Endian_AviStreamHeader(&as);
203
memcpy(&b,&_bih,sizeof(_bih));
204
Endian_BitMapInfo( &b );
205
setStreamInfo (_file, (uint8_t *) &as,
206
(uint8_t *)&b,sizeof(BITMAPINFOHEADER),
207
// MOD Feb 2005 by GMV: ODML support
208
odml_super_idx_size,0,
209
// END MOD Feb 2005 by GMV
213
setStreamInfo (_file, (uint8_t *) &_videostream,
214
(uint8_t *)&_bih,sizeof(BITMAPINFOHEADER),
215
// MOD Feb 2005 by GMV: ODML support
216
odml_super_idx_size,0,
217
// END MOD Feb 2005 by GMV
224
typedef struct VBRext
229
uint16_t nblocksize ;
230
uint16_t nframesperblock ;
231
uint16_t ncodecdelay ;
235
//________________________________________________
236
// Beginning of the write process
237
// We fill-in the headers
238
// 3- Write audio headers
239
// That one can be used several times so we pass stuff
241
//_______________________________________________
242
static uint32_t aacBitrate[16]=
244
96000, 88200, 64000, 48000,
245
44100, 32000, 24000, 22050,
246
16000, 12000, 11025, 8000,
250
uint8_t aviWrite::writeAudioHeader ( AVDMGenericAudioStream * stream, AVIStreamHeader *header
251
// MOD Feb 2005 by GMV: ODML support
252
,uint8_t odml_stream_nbr
253
// END MOD Feb 2005 by GMV
256
// MOD Feb 2005 by GMV: audio super index length
257
uint32_t odml_super_idx_size=24+odml_nbrof_index*16;
258
// END MOD Feb 2005 by GMV
260
// pre compute some headers with extra data in...
261
uint8_t wmaheader[12];
263
uint8_t aacHeader[12];
267
if(!stream) return 1;
269
memset(wmaheader,0,12);
270
memset(&mp3vbr,0,sizeof(mp3vbr));
272
wmaheader[16-16]=0x0a;
273
wmaheader[19-16]=0x08;
274
wmaheader[22-16]=0x01;
275
wmaheader[24-16]=0x74;
278
memcpy(&wav,stream->getInfo (),sizeof(wav));
281
memset (header, 0, sizeof (AVIStreamHeader));
282
header->fccType = fourCC::get ((uint8_t *) "auds");
283
header->dwInitialFrames = 0;
285
header->dwRate = wav.byterate;
286
header->dwSampleSize = 1;
287
header->dwQuality = 0xffffffff;
288
header->dwSuggestedBufferSize = 8000;
289
header->dwLength = stream->getLength ();
295
header->dwScale = wav.blockalign;
296
header->dwSampleSize = 1;
297
header->dwInitialFrames =1;
298
header->dwSuggestedBufferSize=2048;
302
// nb sample in stream
305
len=_videostream.dwLength;
307
len/=_videostream.dwRate;
308
len*=_videostream.dwScale;
312
header->dwLength= floor(len);//_videostream.dwLength;
316
header->dwInitialFrames=0;
317
header->dwRate=wav.frequency;
321
header->dwScale=1024; //sample/packet 1024 seems good for aac
322
header->dwSampleSize = 0;
323
header->dwSuggestedBufferSize=8192;
324
header->dwInitialFrames = 0;
326
// header->dwLength= _videostream.dwLength;
328
wav.bitspersample = 0;
330
//*b++ = (BYTE)((profile +1) << 3 | (SRI >> 1));
331
//*b++ = (BYTE)(((SRI & 0x1) << 7) | (aacsource->GetChannelCount() << 3));
333
int SRI=4; // Default 44.1 khz
334
for(int i=0;i<16;i++) if(wav.frequency==aacBitrate[i]) SRI=i;
337
aacHeader[2]=(2<<3)+(SRI>>1); // Profile LOW
338
aacHeader[3]=((SRI&1)<<7)+((wav.channels)<<3);
341
extra=&(aacHeader[0]);
346
// then update VBR fields
347
mp3vbr.cbsize = R16(12);
349
mp3vbr.fdwflags = R32(2);
350
mp3vbr.nframesperblock = R16(1);
351
mp3vbr.ncodecdelay = 0;
353
wav.bitspersample = 0;
354
mp3vbr.nblocksize=R16(0x180); //384; // ??
357
header->dwInitialFrames = 1;
358
extra=(uint8_t *)&mp3vbr;
359
extraLen=sizeof(mp3vbr);
360
if (stream->isVBR()) //wav->blockalign ==1152) // VBR audio
361
{ // We do like nandub do
362
//ADM_assert (audiostream->asTimeTrack ());
363
wav.blockalign = 1152; // just a try
364
wav.bitspersample = 16;
366
header->dwRate = wav.frequency; //wav->byterate;
367
header->dwScale = wav.blockalign;
368
header->dwLength= _videostream.dwLength;
370
header->dwSampleSize = 0;
371
printf ("\n VBR audio detected\n");
373
// use extended headers
376
mp3vbr.nblocksize=1152;
392
header->dwScale = wav.blockalign;
393
header->dwSampleSize = wav.blockalign;
394
header->dwInitialFrames =1;
395
header->dwSuggestedBufferSize=10*wav.blockalign;
397
extra=(uint8_t *)&wmaheader;
400
case WAV_8BITS_UNSIGNED:
401
wav.encoding=WAV_PCM;
412
#ifdef ADM_BIG_ENDIAN
413
// in case of Little endian, do the usual swap crap
417
memcpy(&as,header,sizeof(as));
418
Endian_AviStreamHeader(&as);
419
memcpy(&w,&wav,sizeof(w));
420
Endian_WavHeader( &w );
421
setStreamInfo (_file,
423
(uint8_t *)&w,sizeof(WAVHeader),
424
// MOD Feb 2005 by GMV: ODML support
425
odml_super_idx_size,odml_stream_nbr,
426
// END MOD Feb 2005 by GMV
430
setStreamInfo (_file,
432
(uint8_t *) &wav, sizeof (WAVHeader),
433
// MOD Feb 2005 by GMV: ODML support
434
odml_super_idx_size,odml_stream_nbr,
435
// END MOD Feb 2005 by GMV
436
extra,extraLen, 0x1000);
442
//_______________________________________________________
444
// Begin to save, built header and prepare structure
445
// The nb frames is indicative but the real value
446
// must be smaller than this parameter
448
//_______________________________________________________
449
uint8_t aviWrite::saveBegin (char *name,
450
MainAVIHeader *inmainheader,
452
AVIStreamHeader * invideostream,
453
BITMAPINFOHEADER *bih,
455
uint32_t videoextraLen,
456
AVDMGenericAudioStream * inaudiostream,
457
AVDMGenericAudioStream * inaudiostream2)
463
ADM_assert (_out == NULL);
464
if (!(_out = qfopen (name, "wb")))
466
printf("Problem writing : %s\n",name);
470
if(!_file->open(_out))
472
printf("Cannot create ADMfileio\n");
481
// update avi header according to the information WE want
483
memcpy (&_mainheader, inmainheader, sizeof (MainAVIHeader));
484
_mainheader.dwFlags = AVIF_HASINDEX + AVIF_ISINTERLEAVED;
488
// update main header codec with video codev
491
_mainheader.dwStreams = 2;
495
_mainheader.dwStreams = 1;
499
printf("\n +++Dual audio stream...\n");
500
_mainheader.dwStreams ++;
504
_mainheader.dwTotalFrames = nb_frame;
505
// Idem for video stream
507
memcpy (&_videostream, invideostream, sizeof (AVIStreamHeader));
508
_videostream.dwLength = nb_frame;
509
_videostream.fccType=fourCC::get((uint8_t *)"vids");
510
memcpy(&_bih,bih,sizeof(_bih));
512
// Update usecperframe
514
f=_videostream.dwRate;
516
f/=_videostream.dwScale;
517
_mainheader.dwMicroSecPerFrame=ADM_UsecFromFps1000( (uint32_t)floor(f));
520
// Recompute image size
522
is=_bih.biWidth*_bih.biHeight;
523
is*=(_bih.biBitCount+7)/8;
528
// MOD Feb 2005 by GMV: initialize ODML data
529
// test for free data structures
530
if(odml_indexes!=NULL){
531
aprintf("\n ODML writer error: data structures not empty for init!");
534
// set generation mode
535
uint32_t pref_odml=0;
537
if(!prefs->get(FEATURE_USE_ODML, &pref_odml))
542
doODML=NO; // only option for users without largefile support
543
#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
545
doODML=HIDDEN; // default; TODO: user should be able to choose NO for plain avi
548
// get number of streams
549
odml_nbrof_streams=_mainheader.dwStreams;
550
aprintf("\nnumber of streams: %lu\n",odml_nbrof_streams);
551
// get number of frames per index
553
odml_index_size=(long)ceil(1000000.0/(double)_mainheader.dwMicroSecPerFrame*600.0); // one index per 10 Minutes; decrease if 4GB are not enough for this amount of time
554
aprintf("\n old number of frames per index: %lu\n",odml_index_size);
555
double fps=invideostream->dwRate/invideostream->dwScale;
557
aprintf("Fps1000:%f\n",fps);
558
fps=600*fps; // 10 mn worth;
559
odml_index_size=(int)floor(fps);
561
aprintf("\nnumber of frames per index: %lu\n",odml_index_size);
562
// get number or indexes per stream
563
odml_nbrof_index=(long)ceil((double)nb_frame/(double)odml_index_size);
564
aprintf("\nnumber of indexes per stream: %lu\n",odml_nbrof_index);
565
// init some other values
567
odml_riff_fpos[0]=0;odml_riff_fpos[1]=0;odml_riff_fpos[2]=0;odml_riff_fpos[3]=0;
570
// create odml index data structure
571
odml_indexes=(odml_super_index_t*) ADM_alloc (sizeof(odml_super_index_t) * odml_nbrof_streams); // super index list
572
memset(odml_indexes,0,sizeof(odml_super_index_t) * odml_nbrof_streams);
573
for(int a=0;a<odml_nbrof_streams;++a){ // for each stream -> one super index
574
odml_indexes[a].odml_index= (odml_index_t*) ADM_alloc (sizeof(odml_index_t) * odml_nbrof_index); // index list
575
memset(odml_indexes[a].odml_index,0,sizeof(odml_index_t) * odml_nbrof_index);
576
for(int b=0;b<odml_nbrof_index;++b){ // for each index
577
odml_indexes[a].odml_index[b].index=(odml_index_data_t*) ADM_alloc (sizeof(odml_index_data_t) * odml_index_size); // index data
578
memset(odml_indexes[a].odml_index[b].index,0,sizeof(odml_index_data_t) * odml_index_size);
579
odml_indexes[a].odml_index[b].nEntriesInUse=0; // (redundant)
582
odml_indexes[a].index_count=0;
585
// END MOD Feb 2005 by GMV
587
//___________________
589
//___________________
593
writeVideoHeader(videoextra,videoextraLen );
595
// MOD Feb 2005 by GMV: ODML support
596
/*writeAudioHeader ( inaudiostream , &_audio1 );
597
writeAudioHeader ( inaudiostream2, &_audio2);*/
598
writeAudioHeader ( inaudiostream , &_audio1,1);
599
writeAudioHeader ( inaudiostream2, &_audio2,2);
600
// odml header placeholder
601
odml_write_dummy_chunk(LMain, &odml_header_fpos, 16);
602
// END MOD Feb 2005 by GMV
609
ADM_assert (!LMovie);
611
LMovie = new AviList ("LIST", _file);
612
LMovie->Begin ("movi");
614
// the *2 is for audio and video
615
// the *3 if for security sake
616
myindex = (IdxEntry *) ADM_alloc (sizeof (IdxEntry) * (nb_frame * 4));
622
//_______________________________________________________
623
// Write video frames and update index accordingly
624
//_______________________________________________________
625
uint8_t aviWrite::saveVideoFrame (uint32_t len, uint32_t flags, uint8_t * data)
628
// MOD Feb 2005 by GMV: interleave ODML index dummy and index frame
629
// write initial index chunks
630
if(vframe==2 && doODML!=NO){ // apparently some players require a video frame at first in the movi list, so we put the initial index dummys behind it (bye bye index before data)
631
odml_write_dummy_chunk(LMovie, &(odml_indexes[0].odml_index[0].fpos), 24+8*odml_index_size);
632
if(odml_nbrof_streams>1)
633
odml_write_dummy_chunk(LMovie, &(odml_indexes[1].odml_index[0].fpos), 24+8*odml_index_size);
634
if(odml_nbrof_streams>2)
635
odml_write_dummy_chunk(LMovie, &(odml_indexes[2].odml_index[0].fpos), 24+8*odml_index_size);
638
odml_riff_break(len+8); // data size + fcc + size info (padding is handled in odml_riff_break)
640
if(!odml_index_frame(0, len,flags&AVI_KEY_FRAME)){
641
aprintf("\ncan not index video frame %lu\n",vframe);
643
// END MOD Feb 2005 by GMV
644
return saveFrame (len, flags, data, (uint8_t *) "00dc");
648
uint8_t aviWrite::saveAudioFrame (uint32_t len, uint8_t * data)
651
// MOD Feb 2005 by GMV: index frame and interleave ODML index dummy
652
odml_riff_break(len+8); // data size + fcc + size info (padding is handled in odml_riff_break)
653
if(!odml_index_frame(1, len,false)){
654
aprintf("\ncan not index audio frame %lu\n",asize);
656
// END MOD Feb 2005 by GMV
657
return saveFrame (len, (uint32_t) 0, data, (uint8_t *) "01wb");
659
uint8_t aviWrite::saveAudioFrameDual (uint32_t len, uint8_t * data)
662
// MOD Feb 2005 by GMV: index frame and interleave ODML index dummy
663
odml_riff_break(len+8); // data size + fcc + size info (padding is handled in odml_riff_break)
664
if(!odml_index_frame(2, len,false)){
665
aprintf("\ncan not index audio (dual) frame %lu\n",asize);
667
// END MOD Feb 2005 by GMV
668
return saveFrame (len, (uint32_t) 0, data, (uint8_t *) "02wb");
673
uint8_t aviWrite::saveFrame (uint32_t len, uint32_t flags,
674
uint8_t * data, uint8_t * fcc)
677
// offset of this chunk compared to the beginning
678
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
679
//offset = LMovie->Tell () - 8 - LMovie->TellBegin ();
681
offset = LMovie->Tell () - 8 - LMovie->TellBegin ();
683
// END MOD Feb 2005 by GMV
684
LMovie->WriteChunk (fcc, len, data);
685
// Now store the index part
687
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
689
// END MOD Feb 2005 by GMV
690
myindex[curindex].fcc = fourCC::get (fcc);
691
myindex[curindex].len = len;
692
myindex[curindex].flags = flags;
693
myindex[curindex].offset = offset;
695
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
697
// END MOD Feb 2005 by GMV
701
//_______________________________________________________
703
//_______________________________________________________
704
uint8_t aviWrite::setEnd (void)
707
// First close the movie
713
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
715
// END MOD Feb 2005 by GMV
716
printf ("\n writing %lu index parts", curindex);
717
printf ("\n received %lu video parts", vframe);
719
// Updating compared to what has been really written
723
LAll->Write32 ("idx1");
724
LAll->Write32 (curindex * 16);
726
for (uint32_t i = 0; i < curindex; i++)
728
LAll->Write32 (myindex[i].fcc);
729
LAll->Write32 (myindex[i].flags);
730
LAll->Write32 (myindex[i].offset); // abs position
731
LAll->Write32 (myindex[i].len);
733
// MOD Feb 2005 by GMV: do not write idx1 in case of ODML
735
// END MOD Feb 2005 by GMV
743
printf ("\n Updating headers...\n");
745
// MOD Feb 2005 by GMV: ODML header and index
747
odml_write_sindex(0, "00dc"); // video super index
748
if(odml_nbrof_streams>1)odml_write_sindex(1,"01wb"); // audio super index
749
if(odml_nbrof_streams>2)odml_write_sindex(2,"02wb"); // audio super index (dual)
751
_file->seek(odml_header_fpos);
752
AviList* LHeader = new AviList("LIST", _file);
753
LHeader->Begin("odml");
754
LHeader->Write32("dmlh");
755
LHeader->Write32((uint32_t)4); // chunk size
756
LHeader->Write32(vframe); // total number of frames
760
if(!odml_write_index(0, "00dc", "ix00")){ // video indexes
761
aprintf("error writing video indexes");
763
if(odml_nbrof_streams>1)
764
if(!odml_write_index(1, "01wb", "ix01")){ // audio indexes
765
aprintf("error writing audio indexes");
767
if(odml_nbrof_streams>2)
768
if(!odml_write_index(2, "02wb", "ix02")){ // audio indexes (dual)
769
printf("error writing audio (dual) indexes");
772
odml_destroy_index();
773
// END MOD Feb 2005 by GMV
776
// MOD Feb 2005 by GMV: set number or frames in first riff
777
//_mainheader.dwTotalFrames = vframe;
779
_mainheader.dwTotalFrames=odml_frames_inAVI;
781
_mainheader.dwTotalFrames = vframe;
782
// END MOD Feb 2005 by GMV
784
_videostream.dwLength = vframe;
785
//astream.dwLength = asize;
788
updateHeader (&_mainheader, &_videostream, NULL);
791
printf("\n End of movie, \n video frames : %lu\n audio frames : %lu",vframe,asize);
792
// need to update headers now
806
uint8_t aviWrite::setStreamInfo (ADMFile * fo,
808
uint8_t * info, uint32_t infolen,
809
// MOD Feb 2005 by GMV: ODML support
810
uint32_t odml_headerlen,
811
uint8_t odml_stream_nbr,
812
// END MOD Feb 2005 by GMV
813
uint8_t * extra, uint32_t extraLen,
822
alist = new AviList ("LIST", fo);
829
alist->Begin ("strl");
832
alist->WriteChunk ((uint8_t *) "strh", sizeof (AVIStreamHeader),
835
uint8_t *buf=new uint8_t[infolen+extraLen];
837
memcpy(buf,info,infolen);
839
memcpy(infolen+buf,extra,extraLen);
841
alist->WriteChunk ((uint8_t *) "strf", infolen+extraLen, buf);
843
junklen = maxxed - sizeof (AVIStreamHeader) - infolen-extraLen;
844
junk = (uint8_t *) ADM_alloc (junklen);
846
memset (junk,0, junklen);
848
// Fill junk with out info string
849
uint32_t len=strlen("Avidemux");
852
memcpy(junk,"Avidemux",len);
854
alist->WriteChunk ((uint8_t *) "JUNK", junklen, junk);
857
// MOD Feb 2005 by GMV: ODML header
858
odml_write_dummy_chunk(alist, &odml_indexes[odml_stream_nbr].fpos, odml_headerlen);
859
// END MOD Feb 2005 by GMV
868
// return how much has been written
869
uint32_t aviWrite::getPos( void )
872
// we take size of file + index
873
// with 32 bytes per index entry
877
return pos+curindex*4*4;
880
// MOD Feb 2005 by GMV: ODML functions
881
void aviWrite::odml_destroy_index(void){
882
// destroy odml index data structure
885
for(int a=0;a<odml_nbrof_streams;++a){
886
if(odml_indexes[a].odml_index){
887
for(int b=0;b<odml_nbrof_index;++b){
888
if(odml_indexes[a].odml_index[b].index)
889
ADM_dealloc (odml_indexes[a].odml_index[b].index);
891
ADM_dealloc (odml_indexes[a].odml_index);
894
ADM_dealloc (odml_indexes);
899
void aviWrite::odml_write_dummy_chunk(AviList* alist, uint64_t* fpos, uint32_t size){
901
// save file position
903
aprintf("\nwrite dummy chunk at file position %Lu with data size %lu\n",*fpos, size);
904
// generate dummy data
905
uint8_t* dummy=(uint8_t*)ADM_alloc (size);
906
memset(dummy,0,size);
908
alist->WriteChunk ((uint8_t *) "JUNK", size, dummy);
913
bool aviWrite::odml_index_frame(int stream_nbr, uint32_t data_size, bool keyFrame){
915
// ADM_assert(!stream_nbr<odml_nbrof_streams);
916
odml_super_index_t* sidx=odml_indexes+stream_nbr; // access to super index
917
if(sidx->odml_index[sidx->index_count].nEntriesInUse==odml_index_size){ // new index needed?
918
if(sidx->index_count<odml_nbrof_index-1) // can index counter be increased?
919
++(sidx->index_count); // increment index counter
921
aprintf("\nindexes full!!\n");
924
// handle possible riff break
925
odml_riff_break(data_size+8); // data size + fcc + size info (padding is handled in odml_riff_break)
927
odml_write_dummy_chunk(LMovie, &(sidx->odml_index[sidx->index_count].fpos), 24+8*odml_index_size);
928
sidx->odml_index[sidx->index_count].nEntriesInUse=0;
930
odml_index_t* idx=sidx->odml_index+(sidx->index_count); // access to index
931
odml_index_data_t* idxd=idx->index+(idx->nEntriesInUse); // access to unused index data
933
uint64_t pos=LMovie->Tell()+8; // preview position of data
934
idxd->fpos=pos; // store file position of data
937
idxd->size=data_size; //store data size
938
else // if no key frame
939
idxd->size=data_size|0x80000000; //store data size with bit 31 set
941
++(idx->nEntriesInUse); // advance to next free index data entry
945
void aviWrite::odml_write_sindex(int stream_nbr, char* stream_fcc){
946
// Warning: This changes the file position
948
_file->seek(odml_indexes[stream_nbr].fpos);
949
aprintf("\nwriting super index at file pos %Lu\n",odml_indexes[stream_nbr].fpos);
950
AviList* LIndex = new AviList("JUNK", _file); // abused writing aid (don't call Begin or End; the fcc is unused until 'Begin')
951
LIndex->Write32("indx"); // 4cc
952
LIndex->Write32(24+odml_nbrof_index*16); // size
953
LIndex->Write16(4); // wLongsPerEntry
954
LIndex->Write8(0); // bIndexSubType
955
LIndex->Write8(0); // bIndexType (AVI_INDEX_OF_INDEXES)
956
LIndex->Write32(odml_indexes[stream_nbr].index_count+1);// nEntriesInUse
957
LIndex->Write32(stream_fcc); // dwChunkId;
958
LIndex->Write32((uint32_t)0);LIndex->Write32((uint32_t)0);LIndex->Write32((uint32_t)0);// reserved
959
for(uint32_t a=0;a<=odml_indexes[stream_nbr].index_count;++a){ // for each chunk index
960
LIndex->Write64(odml_indexes[stream_nbr].odml_index[a].fpos); //absolute file position
961
LIndex->Write32(32 + 8 * odml_index_size); // complete index chunk size
962
LIndex->Write32(odml_indexes[stream_nbr].odml_index[a].nEntriesInUse); // duration
963
aprintf("\nstream %lu, index %lu EntriesInUse:%lu\n",stream_nbr, a ,odml_indexes[stream_nbr].odml_index[a].nEntriesInUse);
968
bool aviWrite::odml_write_index(int stream_nbr, char* stream_fcc, char* index_fcc){ // write index
969
// Warning: This changes the file position
971
aprintf ("\n writing %lu interleaved ODML indexes for %lu frames in stream %s", odml_indexes[stream_nbr].index_count+1, vframe, stream_fcc);
972
AviList* LIndex = new AviList("JUNK", _file); // abused writing aid (don't call Begin or End; the fcc is unused until 'Begin')
973
for(int a=0;a<=odml_indexes[stream_nbr].index_count;++a){ // for each index
974
odml_index_t* idx=odml_indexes[stream_nbr].odml_index+a; // access to index
975
_file->seek(idx->fpos); // shift file pointer
976
LIndex->Write32(index_fcc); // 4cc
977
LIndex->Write32(24+odml_index_size*8); // data size
978
LIndex->Write16(2); // wLongsPerEntry
979
LIndex->Write8(0); // bIndexSubType
980
LIndex->Write8(1); // bIndexType (AVI_INDEX_OF_CHUNKS)
981
LIndex->Write32(idx->nEntriesInUse); // nEntriesInUse
982
LIndex->Write32(stream_fcc); // dwChunkId;
983
uint64_t base_off=idx->index[0].fpos-8; // lets take the position of the first frame in the index as base
985
LIndex->Write64(base_off); // qwBaseOffset
986
LIndex->Write32((uint32_t)0); // reserved
987
for(int b=0;b<idx->nEntriesInUse;++b){ // for each frame in the current index
988
odml_index_data_t* idxd=idx->index+b; // access to index data
989
rel_pos=idxd->fpos-base_off; // get relative file position
990
if(rel_pos>(uint64_t)4*1024*1024*1024){ // index chunks have a maximum offset of 4GB
991
printf("\nData rate too high for index size. Decrease index duration.\n"); // decrease the multiplicator in saveBegin that calculates odml_index_size
992
printf("base:%Lu abs:%Lu rel:%Lu stream:%lu index:%lu entry:%lu",base_off,idxd->fpos,rel_pos,stream_nbr,a,b);
996
LIndex->Write32(rel_pos); // relative file position
997
LIndex->Write32(idxd->size); // data size
1004
void aviWrite::odml_riff_break(uint32_t len){ // advance to the next riff if required
1009
// preview file position
1010
len2+=LMovie->Tell();
1011
// will we get over the next GB border?
1012
if( len2>((uint64_t)1024*1024*1024*(odml_riff_count+1)) ){
1014
aprintf("\nstarting new (hidden) RIFF at %Lu\n",LMovie->Tell());
1015
if(odml_riff_count<4) // we have only 4 buffers but this has to be enough
1016
odml_write_dummy_chunk(LMovie, odml_riff_fpos+odml_riff_count, 16); // write dummy
1017
if(odml_riff_count==0) odml_frames_inAVI=vframe-1; // rescue number of frames in first AVI (-1 since there may be no audio for the last video frame)
1018
}else{ // restart riff and movie
1019
aprintf("\nstarting new RIFF at %Lu\n",LMovie->Tell());
1023
LAll->Begin ("AVIX");
1024
LMovie->Begin ("movi");
1028
// ODML required for movie?
1030
if( ((uint64_t)getPos()+len+17) >= ((uint64_t)4*1024*1024*1024) ){ //if (written data + new chunk + index (old type) for new chunk + possible padding) does not fit into 4GB
1031
printf("\nswitching to ODML mode at %lu\n",LMovie->Tell());
1032
uint64_t last_pos=LMovie->Tell(); // rescue current file position
1034
for(int a=0;a<4;++a){ // for each hidden riff
1035
if(odml_riff_fpos[a]!=0){
1036
_file->seek(odml_riff_fpos[a]); // set file pointer to start of next riff
1039
LAll->Begin("AVIX");
1040
LMovie->Begin("movi");
1044
_file->seek(last_pos);
1045
// following riffs can start directly
1046
doODML=NORMAL; // write RIFF breaks directly
1051
// END MOD Feb 2005 by GMV