Implemented first cut at avi 2.0 indexing for Qt GUI.
This commit is contained in:
parent
4e1a335f81
commit
2ddfc43bc2
|
@ -342,13 +342,18 @@ gwavi_t::write_avi_header_chunk(FILE *fp)
|
|||
|
||||
if (write_chars_bin(fp, "LIST", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
|
||||
if ((marker = ftell(fp)) == -1)
|
||||
goto ftell_failed;
|
||||
|
||||
if (write_int(fp, 0) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (write_chars_bin(fp, "hdrl", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if (write_avi_header(fp, &avi_header) == -1) {
|
||||
|
||||
if (write_avi_header(fp, &avi_header) == -1)
|
||||
{
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_avi_header() failed\n");
|
||||
return -1;
|
||||
|
@ -356,69 +361,108 @@ gwavi_t::write_avi_header_chunk(FILE *fp)
|
|||
|
||||
if (write_chars_bin(fp, "LIST", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
|
||||
if ((sub_marker = ftell(fp)) == -1)
|
||||
goto ftell_failed;
|
||||
|
||||
if (write_int(fp, 0) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (write_chars_bin(fp, "strl", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if (write_stream_header(fp, &stream_header_v) == -1) {
|
||||
|
||||
if (write_stream_header(fp, &stream_header_v) == -1)
|
||||
{
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_stream_header failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_stream_format_v(fp, &stream_format_v) == -1) {
|
||||
if (write_stream_format_v(fp, &stream_format_v) == -1)
|
||||
{
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_stream_format_v failed\n");
|
||||
return -1;
|
||||
}
|
||||
if ( avi_std >= 2 )
|
||||
{
|
||||
stream_index_v.fpos = ftell(fp);
|
||||
|
||||
if ( write_stream_super_indx(fp, &stream_index_v ) == -1 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((t = ftell(fp)) == -1)
|
||||
goto ftell_failed;
|
||||
|
||||
if (fseek(fp, sub_marker, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
if (write_int(fp, (unsigned int)(t - sub_marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (fseek(fp, t, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
if (avi_header.data_streams == 2) {
|
||||
if (avi_header.data_streams == 2)
|
||||
{
|
||||
if (write_chars_bin(fp, "LIST", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
|
||||
if ((sub_marker = ftell(fp)) == -1)
|
||||
goto ftell_failed;
|
||||
|
||||
if (write_int(fp, 0) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (write_chars_bin(fp, "strl", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if (write_stream_header(fp, &stream_header_a) == -1) {
|
||||
|
||||
if (write_stream_header(fp, &stream_header_a) == -1)
|
||||
{
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_stream_header failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_stream_format_a(fp, &stream_format_a) == -1) {
|
||||
if (write_stream_format_a(fp, &stream_format_a) == -1)
|
||||
{
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_stream_format_a failed\n");
|
||||
return -1;
|
||||
}
|
||||
if ( avi_std >= 2 )
|
||||
{
|
||||
stream_index_a.fpos = ftell(fp);
|
||||
|
||||
if ( write_stream_super_indx(fp, &stream_index_a ) == -1 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((t = ftell(fp)) == -1)
|
||||
goto ftell_failed;
|
||||
|
||||
if (fseek(fp, sub_marker, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
if (write_int(fp, (unsigned int)(t - sub_marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (fseek(fp, t, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
}
|
||||
|
||||
if ((t = ftell(fp)) == -1)
|
||||
goto ftell_failed;
|
||||
|
||||
if (fseek(fp, marker, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
if (write_int(fp, (unsigned int)(t - marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (fseek(fp, t, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
|
@ -463,8 +507,223 @@ int gwavi_t::peak_chunk( FILE *fp, long int idx, char *fourcc, unsigned int *siz
|
|||
return 0;
|
||||
}
|
||||
|
||||
int gwavi_t::write_stream_super_indx(FILE *fp, struct gwavi_super_indx_t *indx)
|
||||
{
|
||||
long long t, sizeMarker;
|
||||
|
||||
if (write_chars_bin(fp, "indx", 4) == -1) // FCC
|
||||
{
|
||||
(void)fprintf(stderr, "write_index: write_chars_bin) failed\n");
|
||||
return -1;
|
||||
}
|
||||
if ((sizeMarker = ftell(fp)) == -1) // size of this chunk
|
||||
{
|
||||
perror("write_index (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(fp, 0) == -1)
|
||||
return -1;
|
||||
|
||||
if (write_short(fp, 4) == -1) // wLongsPerEntry; // must be 4 (size of each entry in aIndex array)
|
||||
return -1;
|
||||
|
||||
if (write_byte(fp, 0) == -1) // bIndexSubType; // must be 0 or AVI_INDEX_2FIELD
|
||||
return -1;
|
||||
|
||||
if (write_byte(fp, 0) == -1) // bIndexType; // must be AVI_INDEX_OF_INDEXES
|
||||
return -1;
|
||||
|
||||
if (write_int(fp, indx->nEntriesInUse) == -1) // nEntriesInUse; // number of entries in aIndex array that
|
||||
return -1;
|
||||
|
||||
if (write_chars_bin(fp, indx->chunkId, 4) == -1) // dwChunkId; // ’##dc’ or ’##db’ or ’##wb’, etc
|
||||
return -1;
|
||||
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
if (write_int(fp, 0) == -1) // dwReserved[3]; // must be 0
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i=0; i<32; i++)
|
||||
{
|
||||
if (write_int64(fp, indx->aIndex[i].qwOffset) == -1) //qwOffset; // absolute file offset, offset 0 is
|
||||
return -1;
|
||||
|
||||
if (write_int(fp, indx->aIndex[i].dwSize) == -1) // dwSize; // size of index chunk at this offset
|
||||
return -1;
|
||||
|
||||
if (write_int(fp, indx->aIndex[i].dwDuration) == -1) // dwDuration; // time span in stream ticks
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((t = ftell(fp)) == -1)
|
||||
{
|
||||
perror("write_index (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(fp, sizeMarker, SEEK_SET) == -1)
|
||||
{
|
||||
perror("write_index (fseek)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(fp, (unsigned int)(t - sizeMarker - 4)) == -1)
|
||||
return -1;
|
||||
|
||||
if (fseek(fp, t, SEEK_SET) == -1)
|
||||
{
|
||||
perror("write_index (fseek)");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gwavi_t::write_stream_std_indx(FILE *fp, struct gwavi_super_indx_t *indx)
|
||||
{
|
||||
char fcc[8];
|
||||
long long t, sizeMarker, std_indx_ofs, qwBaseOffset = 0;
|
||||
unsigned int chunkSize = 0, numEntries = 0;
|
||||
|
||||
std_indx_ofs = ftell(fp);
|
||||
|
||||
sprintf( fcc, "ix%02i", indx->streamId );
|
||||
|
||||
if (write_chars_bin(fp, fcc, 4) == -1) // FCC
|
||||
{
|
||||
(void)fprintf(stderr, "write_index: write_chars_bin) failed\n");
|
||||
return -1;
|
||||
}
|
||||
if ((sizeMarker = ftell(fp)) == -1) // size of this chunk
|
||||
{
|
||||
perror("write_index (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(fp, chunkSize) == -1)
|
||||
return -1;
|
||||
|
||||
if (write_short(fp, 2) == -1) // wLongsPerEntry; // must be 2 (sizeof(aIndex[0])/sizeof(DWORD))
|
||||
return -1;
|
||||
|
||||
if (write_byte(fp, 0) == -1) // bIndexSubType; // must be 0
|
||||
return -1;
|
||||
|
||||
if (write_byte(fp, 0x01) == -1) // bIndexType; // must be AVI_INDEX_OF_CHUNKS
|
||||
return -1;
|
||||
|
||||
if (write_int(fp, numEntries) == -1) // nEntriesInUse; // number of entries in aIndex array that
|
||||
return -1;
|
||||
|
||||
if (write_chars_bin(fp, indx->chunkId, 4) == -1) // dwChunkId; // ’##dc’ or ’##db’ or ’##wb’, etc
|
||||
return -1;
|
||||
|
||||
if (write_int64(fp, qwBaseOffset) == -1) //qwBaseOffset; // all dwOffsets in aIndex array are relative to this
|
||||
return -1;
|
||||
|
||||
if (write_int(fp, 0) == -1) // dwReserved3; // must be 0
|
||||
return -1;
|
||||
|
||||
for (size_t i=0; i<offsets.size(); i++)
|
||||
{
|
||||
unsigned int dwOffset, dwSize;
|
||||
|
||||
if ( offsets[i].type != indx->streamId )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ( qwBaseOffset == 0 )
|
||||
{
|
||||
qwBaseOffset = offsets[i].fofs;
|
||||
}
|
||||
dwOffset = offsets[i].fofs - qwBaseOffset + 8;
|
||||
|
||||
if (write_int(fp, dwOffset) == -1) // qwBaseOffset + this is absolute file offset
|
||||
return -1;
|
||||
|
||||
dwSize = offsets[i].len;
|
||||
|
||||
if ( !offsets[i].keyFrame )
|
||||
{
|
||||
dwSize |= 0x80000000;
|
||||
}
|
||||
|
||||
if (write_int(fp, dwSize) == -1) // bit 31 is set if this is NOT a keyframe
|
||||
return -1;
|
||||
|
||||
numEntries++;
|
||||
}
|
||||
|
||||
if ((t = ftell(fp)) == -1)
|
||||
{
|
||||
perror("write_index (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(fp, sizeMarker, SEEK_SET) == -1)
|
||||
{
|
||||
perror("write_index (fseek)");
|
||||
return -1;
|
||||
}
|
||||
chunkSize = t - sizeMarker - 4;
|
||||
|
||||
if (write_int(fp, chunkSize) == -1)
|
||||
return -1;
|
||||
|
||||
if (write_short(fp, 2) == -1) // wLongsPerEntry; // must be 2 (sizeof(aIndex[0])/sizeof(DWORD))
|
||||
return -1;
|
||||
|
||||
if (write_byte(fp, 0) == -1) // bIndexSubType; // must be 0
|
||||
return -1;
|
||||
|
||||
if (write_byte(fp, 0x01) == -1) // bIndexType; // must be AVI_INDEX_OF_CHUNKS
|
||||
return -1;
|
||||
|
||||
if (write_int(fp, numEntries) == -1) // nEntriesInUse; // number of entries in aIndex array that
|
||||
return -1;
|
||||
|
||||
if (write_chars_bin(fp, indx->chunkId, 4) == -1) // dwChunkId; // ’##dc’ or ’##db’ or ’##wb’, etc
|
||||
return -1;
|
||||
|
||||
if (write_int64(fp, qwBaseOffset) == -1) //qwBaseOffset; // all dwOffsets in aIndex array are relative to this
|
||||
return -1;
|
||||
|
||||
if (fseek(fp, t, SEEK_SET) == -1)
|
||||
{
|
||||
perror("write_index (fseek)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( indx->nEntriesInUse < 32 )
|
||||
{
|
||||
int i = indx->nEntriesInUse;
|
||||
|
||||
indx->aIndex[i].qwOffset = std_indx_ofs;
|
||||
indx->aIndex[i].dwSize = chunkSize;
|
||||
indx->aIndex[i].dwDuration = 0;
|
||||
|
||||
indx->nEntriesInUse++;
|
||||
}
|
||||
|
||||
if (fseek(fp, indx->fpos, SEEK_SET) == -1)
|
||||
{
|
||||
perror("write_index (fseek)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( write_stream_super_indx( fp, indx ) == -1 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fseek(fp, t, SEEK_SET) == -1)
|
||||
{
|
||||
perror("write_index (fseek)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_index(FILE *fp)
|
||||
gwavi_t::write_index1(FILE *fp)
|
||||
{
|
||||
long long marker, t;
|
||||
unsigned int offset = 4;
|
||||
|
|
|
@ -61,10 +61,16 @@ gwavi_t::write_int(FILE *out, unsigned int n)
|
|||
{
|
||||
unsigned char buffer[4];
|
||||
|
||||
buffer[0] = n;
|
||||
buffer[1] = n >> 8;
|
||||
buffer[2] = n >> 16;
|
||||
buffer[3] = n >> 24;
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
buffer[i] = (n & 0x000000FF);
|
||||
|
||||
n = n >> 8;
|
||||
}
|
||||
//buffer[0] = n;
|
||||
//buffer[1] = n >> 8;
|
||||
//buffer[2] = n >> 16;
|
||||
//buffer[3] = n >> 24;
|
||||
|
||||
if (fwrite(buffer, 1, 4, out) != 4)
|
||||
return -1;
|
||||
|
@ -72,13 +78,46 @@ gwavi_t::write_int(FILE *out, unsigned int n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_int64(FILE *out, unsigned long long int n)
|
||||
{
|
||||
unsigned char buffer[8];
|
||||
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
buffer[i] = (n & 0x000000FFllu);
|
||||
|
||||
n = n >> 8;
|
||||
}
|
||||
|
||||
if (fwrite(buffer, 1, 8, out) != 8)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_byte(FILE *out, unsigned char n)
|
||||
{
|
||||
if (fwrite( &n, 1, 1, out) != 1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_short(FILE *out, unsigned int n)
|
||||
{
|
||||
unsigned char buffer[2];
|
||||
|
||||
buffer[0] = n;
|
||||
buffer[1] = n >> 8;
|
||||
for (int i=0; i<2; i++)
|
||||
{
|
||||
buffer[i] = (n & 0x000000FF);
|
||||
|
||||
n = n >> 8;
|
||||
}
|
||||
//buffer[0] = n;
|
||||
//buffer[1] = n >> 8;
|
||||
|
||||
if (fwrite(buffer, 1, 2, out) != 2)
|
||||
return -1;
|
||||
|
|
|
@ -73,11 +73,13 @@ gwavi_t::gwavi_t(void)
|
|||
memset( &stream_format_v, 0, sizeof(struct gwavi_stream_format_v_t) );
|
||||
memset( &stream_header_a, 0, sizeof(struct gwavi_stream_header_t) );
|
||||
memset( &stream_format_a, 0, sizeof(struct gwavi_stream_format_a_t) );
|
||||
memset( &stream_index_v , 0, sizeof(struct gwavi_super_indx_t) );
|
||||
memset( &stream_index_a , 0, sizeof(struct gwavi_super_indx_t) );
|
||||
memset( fourcc, 0, sizeof(fourcc) );
|
||||
marker = 0;
|
||||
movi_fpos = 0;
|
||||
bits_per_pixel = 24;
|
||||
|
||||
avi_std = 2;
|
||||
}
|
||||
|
||||
gwavi_t::~gwavi_t(void)
|
||||
|
@ -205,6 +207,9 @@ gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
|
|||
stream_format_v.palette = 0;
|
||||
stream_format_v.palette_count = 0;
|
||||
|
||||
strcpy( stream_index_v.chunkId, "00dc");
|
||||
stream_index_v.streamId = 0;
|
||||
|
||||
if (audio)
|
||||
{
|
||||
/* set stream header */
|
||||
|
@ -232,6 +237,9 @@ gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
|
|||
audio->channels * (audio->bits / 8);
|
||||
stream_format_a.bits_per_sample = audio->bits;
|
||||
stream_format_a.size = 0;
|
||||
|
||||
strcpy( stream_index_a.chunkId, "01wb");
|
||||
stream_index_a.streamId = 1;
|
||||
}
|
||||
|
||||
if (write_chars_bin(out, "RIFF", 4) == -1)
|
||||
|
@ -312,6 +320,7 @@ gwavi_t::add_frame( unsigned char *buffer, size_t len, unsigned int flags)
|
|||
|
||||
//printf("Frame Offset: %li\n", ftell(out) - movi_fpos );
|
||||
|
||||
idx.fofs = ftell(out);
|
||||
idx.len = len;
|
||||
idx.type = 0;
|
||||
idx.keyFrame = (flags & IF_KEYFRAME) ? 1 : 0;
|
||||
|
@ -374,6 +383,7 @@ gwavi_t::add_audio( unsigned char *buffer, size_t len)
|
|||
maxi_pad = WORD_SIZE - maxi_pad;
|
||||
}
|
||||
|
||||
idx.fofs = ftell(out);
|
||||
idx.len = len;
|
||||
idx.type = 1;
|
||||
idx.keyFrame = 1;
|
||||
|
@ -438,13 +448,26 @@ gwavi_t::close(void)
|
|||
if (fseek(out,t,SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
if (write_index(out) == -1)
|
||||
if ( avi_std < 2 )
|
||||
{
|
||||
(void)fprintf(stderr, "gwavi_close: write_index() failed\n");
|
||||
return -1;
|
||||
if (write_index1(out) == -1)
|
||||
{
|
||||
(void)fprintf(stderr, "gwavi_close: write_index() failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( write_stream_std_indx( out, &stream_index_v ) == -1 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if ( write_stream_std_indx( out, &stream_index_a ) == -1 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//free(offsets);
|
||||
offsets.clear();
|
||||
|
||||
/* reset some avi header fields */
|
||||
|
|
|
@ -142,8 +142,23 @@ struct gwavi_audio_t
|
|||
unsigned int samples_per_second;
|
||||
};
|
||||
|
||||
struct gwavi_super_indx_t
|
||||
{
|
||||
unsigned long long fpos;
|
||||
unsigned int nEntriesInUse;
|
||||
char chunkId[7];
|
||||
char streamId;
|
||||
|
||||
struct {
|
||||
unsigned long long qwOffset;
|
||||
unsigned int dwSize;
|
||||
unsigned int dwDuration;
|
||||
} aIndex[32];
|
||||
};
|
||||
|
||||
struct gwavi_index_rec_t
|
||||
{
|
||||
long long fofs;
|
||||
unsigned int len;
|
||||
unsigned char type;
|
||||
unsigned char keyFrame;
|
||||
|
@ -189,12 +204,15 @@ class gwavi_t
|
|||
struct gwavi_header_t avi_header;
|
||||
struct gwavi_stream_header_t stream_header_v;
|
||||
struct gwavi_stream_format_v_t stream_format_v;
|
||||
struct gwavi_super_indx_t stream_index_v;
|
||||
struct gwavi_stream_header_t stream_header_a;
|
||||
struct gwavi_stream_format_a_t stream_format_a;
|
||||
struct gwavi_super_indx_t stream_index_a;
|
||||
long long marker;
|
||||
std::vector <gwavi_index_rec_t> offsets;
|
||||
long long movi_fpos;
|
||||
int bits_per_pixel;
|
||||
int avi_std;
|
||||
char fourcc[8];
|
||||
|
||||
// helper functions
|
||||
|
@ -207,10 +225,14 @@ class gwavi_t
|
|||
struct gwavi_stream_format_v_t *stream_format_v);
|
||||
int write_stream_format_a(FILE *fp,
|
||||
struct gwavi_stream_format_a_t *stream_format_a);
|
||||
int write_stream_std_indx(FILE *fp, struct gwavi_super_indx_t *indx);
|
||||
int write_stream_super_indx(FILE *fp, struct gwavi_super_indx_t *indx);
|
||||
int write_avi_header_chunk( FILE *fp );
|
||||
int write_index(FILE *fp);
|
||||
int write_index1(FILE *fp);
|
||||
int check_fourcc(const char *fourcc);
|
||||
int write_int(FILE *fp, unsigned int n);
|
||||
int write_int64(FILE *out, unsigned long long int n);
|
||||
int write_byte(FILE *fp, unsigned char n);
|
||||
int write_short(FILE *fp, unsigned int n);
|
||||
int write_chars(FILE *fp, const char *s);
|
||||
int write_chars_bin(FILE *fp, const char *s, int count);
|
||||
|
|
Loading…
Reference in New Issue