Implemented first cut at avi 2.0 indexing for Qt GUI.

This commit is contained in:
mjbudd77 2021-09-02 21:13:54 -04:00
parent 4e1a335f81
commit 2ddfc43bc2
4 changed files with 362 additions and 19 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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);