📄 decapsavi.cpp
字号:
this->video_pos = 0;
mb->Free();
return 1;
}
int MediaDecapsAVI::AddIndexEntry(char *tag,
long flags,
long pos,
long len)
{
void *ptr;
if(this->n_idx*16 >= this->max_idx)
{
ptr = realloc((void *)this->idx,
(this->max_idx + 4096) * 16);
if(ptr == 0) {
return -1;
}
this->max_idx += 4096;
this->idx = (char((*)[16]) ) ptr;
}
memcpy(this->idx[this->n_idx], tag, 4);
long2str(this->idx[this->n_idx]+ 4, flags);
long2str(this->idx[this->n_idx]+ 8, pos);
long2str(this->idx[this->n_idx]+12, len);
this->n_idx++;
return 0;
}
int MediaDecapsAVI::ReFillIndex()
{
unsigned long n;
long idx_type;
long i;
long nvi, nai, ioff;
long tot;
MediaBuffer *mb = new MediaBuffer();
if(this->input == NULL)
return MP_RESULT_ERROR;
mb->Alloc(256);
this->input->Seek(this->movi_start, INPUT_SEEK_SET);
this->max_idx = 4096;
this->n_idx = 0;
this->idx = (char((*)[16]) ) realloc(this->idx, this->max_idx*16);
while(1)
{
if( this->input->Read(mb, 8) != 8 )
break;
n = str2ulong((char *) mb->GetData() + 4);
if(strncmp((char *) mb->GetData(), "LIST", 4) == 0)
{
this->input->Seek(4, INPUT_SEEK_CUR);
continue;
}
if( ((((char *) mb->GetData())[2]=='d' || ((char *) mb->GetData())[2]=='D') &&
(((char *) mb->GetData())[3]=='b' || ((char *) mb->GetData())[3]=='B' ||
((char *) mb->GetData())[3]=='c' || ((char *) mb->GetData())[3]=='C') ) ||
((((char *) mb->GetData())[2]=='w' || ((char *) mb->GetData())[2]=='W') &&
(((char *) mb->GetData())[3]=='b' || ((char *) mb->GetData())[3]=='B') ) )
{
this->AddIndexEntry(((char *) mb->GetData()),
0,
this->input->Seek(0, INPUT_SEEK_CUR) - 8,
n);
}
this->input->Seek(PAD_EVEN(n), INPUT_SEEK_CUR);
}
idx_type = 1;
nvi = 0;
nai = 0;
for(i=0; i < this->n_idx; i++)
{
if(strncmp(this->idx[i], this->video_tag, 3) == 0)
nvi++;
if(strncmp(this->idx[i], this->audio_tag, 4) == 0)
nai++;
}
this->video_frames = nvi;
this->audio_chunks = nai;
if(this->video_frames == 0)
return 0;
this->video_index = (video_index_entry *) realloc(this->video_index, nvi*sizeof(video_index_entry));
if(this->video_index == 0)
return 0;
if(this->audio_chunks)
{
this->audio_index = (audio_index_entry *) realloc(this->audio_index, nai*sizeof(audio_index_entry));
if(this->audio_index==0) {
mb->Free();
return 0;
}
}
nvi = 0;
nai = 0;
tot = 0;
ioff = idx_type == 1 ? 8 : this->movi_start+4;
for(i=0; i < this->n_idx; i++)
{
if(strncmp(this->idx[i], this->video_tag, 3) == 0)
{
this->video_index[nvi].flags = str2ulong(this->idx[i]+ 4);
this->video_index[nvi].pos = str2ulong(this->idx[i]+ 8)+ioff;
this->video_index[nvi].len = str2ulong(this->idx[i]+12);
nvi++;
}
if(strncmp(this->idx[i], this->audio_tag, 4) == 0)
{
this->audio_index[nai].pos = str2ulong(this->idx[i]+ 8)+ioff;
this->audio_index[nai].len = str2ulong(this->idx[i]+12);
this->audio_index[nai].tot = tot;
tot += this->audio_index[nai].len;
nai++;
}
}
this->audio_bytes = tot;
mb->Free();
return 1;
}
BOOL MediaDecapsAVI::isKeyframe(long frame)
{
if(frame < 0 || frame > this->video_frames)
frame = 0;
if(!this->video_index)
{
return 1;
}
return this->video_index[frame].flags & AVIIF_KEYFRAME;
}
unsigned int MediaDecapsAVI::GetNumberOfVideoStreams()
{
return 1;
}
unsigned int MediaDecapsAVI::GetNumberOfAudioStreams()
{
if(this->audio_strn == 99)
return 0;
return this->audio_strn;
}
unsigned int MediaDecapsAVI::GetVideoWidth(unsigned int StreamId)
{
return this->width;
}
unsigned int MediaDecapsAVI::GetVideoHeight(unsigned int StreamId)
{
return this->height;
}
double MediaDecapsAVI::GetVideoFrameRate(unsigned int StreamId)
{
if(this->fps == 0)
this->fps = 25;
if(this->fps == 23)
this->fps = 25;
return this->fps;
}
char *MediaDecapsAVI::GetVideoCompression(unsigned int StreamId)
{
return this->compressor;
}
BITMAPINFOHEADER *MediaDecapsAVI::GetVideoHeader(unsigned int StreamId)
{
return &this->bitmapinfoheader;
}
unsigned long MediaDecapsAVI::GetCurrentVideoFrame(unsigned int StreamId)
{
return this->video_pos;
}
unsigned long MediaDecapsAVI::GetTotalVideoFrames(unsigned int StreamId)
{
return this->video_frames;
}
unsigned long MediaDecapsAVI::GetTotalVideoTime(unsigned int StreamId)
{
if(this->fps == 0) {
return 0;
}
else {
return (unsigned long) (this->video_frames * 1000 / (double) this->fps);
}
}
unsigned int MediaDecapsAVI::GetAudioBits(unsigned int StreamId)
{
return this->a_bits;
}
unsigned int MediaDecapsAVI::GetAudioChannels(unsigned int StreamId)
{
return this->a_chans;
}
unsigned int MediaDecapsAVI::GetAudioFrequency(unsigned int StreamId)
{
return this->a_rate;
}
WAVEFORMATEX *MediaDecapsAVI::GetAudioFormat(unsigned int StreamId)
{
return (WAVEFORMATEX *) &this->waveformatex;
}
unsigned int MediaDecapsAVI::GetNextVideoFrameSize(unsigned int StreamId)
{
if(!this->video_index) {
return 0;
}
return(this->video_index[this->video_pos].len);
}
unsigned int MediaDecapsAVI::ReadVideoFrame(unsigned int StreamId, MediaBuffer *mb)
{
unsigned int m;
unsigned int n;
if(!this->video_index || !mb) {
return MP_RESULT_ERROR;
}
if(this->video_pos < 0 || this->video_pos >= this->video_frames - 1) {
return MP_RESULT_ERROR;
}
WaitForSingleObject(this->hIOMutex, INFINITE);
n = this->video_index[this->video_pos].len;
this->input->Seek(this->video_index[this->video_pos].pos, INPUT_SEEK_SET);
if(mb->GetSize() < n) {
mb->ReAlloc(n);
}
if ((m = this->input->Read(mb, n)) != n) {
this->video_pos++;
ReleaseMutex(this->hIOMutex);
char msg[256];
sprintf(msg, "index %u and %u at %u", this->video_index[this->video_pos].len, this->video_index[this->video_pos].pos, this->video_pos);
MessageBox(NULL, msg, "", MB_OK);
sprintf(msg, "read %d on %u at %d on %d", m, n, this->video_pos, this->video_frames);
MessageBox(NULL, msg, "", MB_OK);
return n;
}
this->video_pos++;
ReleaseMutex(this->hIOMutex);
return MP_RESULT_OK;
}
unsigned int MediaDecapsAVI::ReadAudioData(unsigned int StreamId, char *buffer, unsigned int bytes)
{
unsigned int nr, pos, left = 0, todo, posc, posb, asked_bytes;
MediaBuffer *mbi = new MediaBuffer();
if(!this->audio_index || !buffer) {
return MP_RESULT_ERROR;
}
asked_bytes = bytes;
posc = this->audio_posc;
posb = this->audio_posb;
nr = 0;
mbi->Alloc(bytes);
WaitForSingleObject(this->hIOMutex, INFINITE);
while(bytes > 0) {
left = this->audio_index[this->audio_posc].len - this->audio_posb;
if(left == 0) {
if(this->audio_posc >= this->audio_chunks - 1) {
ReleaseMutex(this->hIOMutex);
this->audio_posb = posb;
this->audio_posc = posc;
return 0;
}
this->audio_posc++;
this->audio_posb = 0;
continue;
}
if(bytes < left)
todo = bytes;
else
todo = left;
pos = this->audio_index[this->audio_posc].pos + this->audio_posb;
this->input->Seek(pos, INPUT_SEEK_SET);
if (this->input->Read(mbi, todo) != todo) {
ReleaseMutex(this->hIOMutex);
this->audio_posb = posb;
this->audio_posc = posc;
return 0;
}
memcpy(buffer + nr, mbi->GetData(), todo);
bytes -= todo;
nr += todo;
this->audio_posb += todo;
}
mbi->Free();
delete mbi;
ReleaseMutex(this->hIOMutex);
return asked_bytes;
}
MP_RESULT MediaDecapsAVI::UpdateForSize()
{
this->ReFillIndex();
return MP_RESULT_OK;
}
MP_RESULT MediaDecapsAVI::SeekAudio(unsigned int StreamId, long bytes)
{
long n0, n1, n;
if(!this->audio_index) {
return MP_RESULT_ERROR;
}
if(bytes < 0)
bytes = 0;
n0 = 0;
n1 = this->audio_chunks;
while(n0 < n1 - 1)
{
n = (n0 + n1) / 2;
if(this->audio_index[n].tot > bytes)
n1 = n;
else
n0 = n;
}
this->audio_posc = n0;
if(this->audio_index[n0].len > 1000) {
this->audio_posb = bytes - this->audio_index[n0].tot;
}
else {
this->audio_posb = 0;
}
return MP_RESULT_OK;
}
MP_RESULT MediaDecapsAVI::SeekVideo(unsigned int StreamId, long frame)
{
if(!this->video_index) {
return MP_RESULT_ERROR;
}
if (frame < 0 ) {
frame = 0;
}
this->video_pos = frame;
return MP_RESULT_OK;
}
MP_RESULT MediaDecapsAVI::ReSeekAudio(unsigned int StreamId)
{
double ratio;
long audio_bytes;
if(this->GetNumberOfAudioStreams() > 0) {
WaitForSingleObject(this->hIOMutex, INFINITE);
ratio = (double) ((double) this->video_pos / (double) this->video_frames);
audio_bytes = (long) (ratio * this->audio_bytes);
audio_bytes -= (audio_bytes % this->waveformatex.nBlockSize);
this->SeekAudio(StreamId, audio_bytes);
ReleaseMutex(this->hIOMutex);
}
return MP_RESULT_OK;
}
MP_RESULT MediaDecapsAVI::Seek(unsigned int videoStreamId, unsigned int audioStreamId, int percent)
{
long frame;
double ratio;
long audio_bytes;
WaitForSingleObject(this->hIOMutex, INFINITE);
frame = (long) (percent * this->video_frames / 100);
while(!this->isKeyframe(frame) && frame < this->video_frames) {
frame++;
}
if(frame >= this->video_frames)
frame = 0;
this->SeekVideo(videoStreamId, frame);
if(this->GetNumberOfAudioStreams() > 0) {
ratio = (double) ((double) frame / (double) this->video_frames);
audio_bytes = (long) (ratio * this->audio_bytes);
audio_bytes -= (audio_bytes % this->waveformatex.nBlockSize);
this->SeekAudio(audioStreamId, audio_bytes);
ReleaseMutex(this->hIOMutex);
return MP_RESULT_OK;
}
ReleaseMutex(this->hIOMutex);
return MP_RESULT_OK;
}
MP_RESULT MediaDecapsAVI::Rewind(unsigned int videoStreamId, unsigned int audioStreamId)
{
this->video_pos = 0;
this->audio_posc = 0;
this->audio_posb = 0;
return MP_RESULT_OK;
}
MP_RESULT MediaDecapsAVI::SeekNextKeyFrame(unsigned int StreamId)
{
WaitForSingleObject(this->hIOMutex, INFINITE);
this->video_pos++;
while(!isKeyframe(this->video_pos) && this->video_pos < this->video_frames)
this->video_pos++;
ReleaseMutex(this->hIOMutex);
return MP_RESULT_OK;
}
MP_RESULT MediaDecapsAVI::SeekPreviousKeyFrame(unsigned int StreamId)
{
WaitForSingleObject(this->hIOMutex, INFINITE);
if(this->video_pos > 1) {
this->video_pos--;
this->video_pos--;
}
while(!isKeyframe(this->video_pos) && this->video_pos > 0)
this->video_pos--;
ReleaseMutex(this->hIOMutex);
return MP_RESULT_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -