Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

645 lines (559 sloc) 13.231 kb
/*
* avi.c: AVI container functions for replex
*
*
* Copyright (C) 2003 Marcus Metzler <mocm@metzlerbros.de>
* Metzler Brothers Systementwicklung GbR
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*/
#include <stdlib.h>
#include <string.h>
#include "mpg_common.h"
#include "avi.h"
#include "replex.h"
#include "pes.h"
#define DEBUG 1
#ifdef DEBUG
#include "mpg_common.h"
#endif
uint32_t getle32(uint8_t *buf)
{
return (buf[3]<<24)|(buf[2]<<16)|(buf[1]<<8)|buf[0];
}
uint32_t getbe32(uint8_t *buf)
{
return (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3];
}
void printhead(uint8_t *buf)
{
printf("%c%c%c%c ", buf[0], buf[1], buf[2], buf[3]);
}
uint32_t getsize(int fd)
{
int len;
uint8_t buf[4];
len=read(fd, buf, 4);
return getle32(buf);
}
uint32_t getsize_buf(uint8_t *buf)
{
return getle32(buf);
}
int check_riff(avi_context *ac, uint8_t *buf, int len)
{
uint32_t tag;
int c = 0;
if (len < 12) return -1;
tag = getle32(buf);
if (tag != TAG_IT('R','I','F','F')) return -1;
c+=4;
ac->riff_end = getle32(buf+c);
c+=4;
tag = getle32(buf+c);
if (tag != TAG_IT('A','V','I',' ') &&
tag != TAG_IT('A','V','I','X') ) return -1;
return c+4;
}
static
int new_idx_frame( avi_context *ac, uint32_t pos, uint32_t len,
uint32_t fl, uint32_t id)
{
int num = ac->num_idx_frames;
if (ac->num_idx_alloc < num+1){
avi_index *idx;
uint32_t newnum = num + 1024;
if (ac->idx){
idx = realloc(ac->idx,
newnum*sizeof(avi_index));
} else {
idx = malloc(newnum*sizeof(avi_index));
}
if (!idx) return -1;
ac->idx = idx;
ac->num_idx_alloc = newnum;
}
ac->idx[num].off = pos;
ac->idx[num].id = id;
ac->idx[num].len = len;
ac->idx[num].flags = fl;
ac->num_idx_frames++;
return 0;
}
void print_index(avi_context *ac, int num){
char *cc;
cc = (char *) &ac->idx[num].id;
fprintf(stderr,"%d chunkid: %c%c%c%c ",
num,
*cc,*(cc+1),*(cc+2),*(cc+3));
fprintf(stderr," chunkoff: 0x%04x ",
(int)ac->idx[num].off);
fprintf(stderr," chunksize: 0x%04x ",
ac->idx[num].len);
fprintf(stderr," chunkflags: 0x%04x \n",
ac->idx[num].flags);
}
int avi_read_index(avi_context *ac, int fd)
{
uint32_t tag;
uint32_t isize;
uint32_t c;
off_t start;
uint8_t buf[16];
char *cc;
if (!(ac->avih_flags & AVI_HASINDEX)) return -2;
fprintf(stderr,"READING INDEX\n");
start = lseek(fd, 0, SEEK_CUR);
lseek(fd, ac->movi_length+ac->movi_start+4, SEEK_SET);
read(fd,buf,4);
tag = getle32(buf);
if (tag != TAG_IT('i','d','x','1')){
cc = (char *) &tag;
fprintf(stderr," tag: %c%c%c%c\n ",*cc,
*(cc+1),*(cc+2),*(cc+3));
lseek(fd, start, SEEK_SET);
return -1;
}
isize = getsize(fd);
c = 0;
while ( c < isize ){
uint32_t chunkid;
uint32_t chunkflags;
uint32_t chunkoff;
uint32_t chunksize;
read(fd,buf,16);
chunkid = getle32(buf);
chunkflags = getle32(buf+4);
chunkoff = getle32(buf+8);
chunksize = getle32(buf+12);
new_idx_frame(ac, chunkoff, chunksize, chunkflags,chunkid);
switch(chunkid){
case TAG_IT('0','1','w','b'):
ac->achunks++;
if (!chunksize) ac->zero_achunks++;
break;
case TAG_IT('0','0','d','c'):
ac->vchunks++;
if (!chunksize) ac->zero_vchunks++;
break;
}
#ifdef DEBUG
/*
print_index(ac,ac->num_idx_frames-1);
*/
#endif
c+=16;
}
#ifdef DEBUG
fprintf(stderr,"Found %d video (%d were empty) and %d audio (%d were empty) chunks\n", (int)ac->vchunks, (int)ac->zero_vchunks, (int)ac->achunks, (int)ac->zero_achunks);
#endif
lseek(fd, start, SEEK_SET);
return 0;
}
int read_avi_header( avi_context *ac, int fd)
{
uint8_t buf[256];
uint32_t tag;
uint32_t size = 0;
int c = 0;
int skip=0;
int n;
#ifdef DEBUG
char *cc;
#endif
while ((c=read(fd, buf, 4))==4) {
skip=0;
tag = getle32(buf);
#ifdef DEBUG
cc = (char *) &tag;
fprintf(stderr,"tag: %c%c%c%c ",*cc,*(cc+1),*(cc+2),*(cc+3));
#endif
switch(tag){
case TAG_IT('L','I','S','T'):
size = getsize(fd);
break;
case TAG_IT('m','o','v','i'):
ac->done=1;
ac->movi_start = lseek(fd, 0, SEEK_CUR);
ac->movi_length = size-8;
#ifdef DEBUG
fprintf(stderr," size: %d",size);
fprintf(stderr," header done\n");
#endif
return 0;
break;
case TAG_IT('h','d','r','l'):
break;
case TAG_IT('s','t','r','l'):
break;
case TAG_IT('J','U','N','K'):
case TAG_IT('s','t','r','f'):
case TAG_IT('s','t','r','d'):
case TAG_IT('s','t','r','n'):
size = getsize(fd);
skip=1;
break;
case TAG_IT('a','v','i','h'):
size = getsize(fd);
c=0;
read(fd,buf,size);
ac->msec_per_frame = getle32(buf+c);
c+=12;
ac->avih_flags = getle32(buf+c);
c+=4;
ac->total_frames = getle32(buf+c);
c+=4;
ac->init_frames = getle32(buf+c);
c+=4;
ac->nstreams = getle32(buf+c);
c+=8;
ac->width = getle32(buf+c);
c+=4;
ac->height = getle32(buf+c);
c+=4;
#ifdef DEBUG
fprintf(stderr," size: %d\n",size);
fprintf(stderr," microsecs per frame %d\n",
ac->msec_per_frame);
if (ac->avih_flags & AVI_HASINDEX)
fprintf(stderr," AVI has index\n");
if (ac->avih_flags & AVI_USEINDEX)
fprintf(stderr," AVI must use index\n");
if (ac->avih_flags & AVI_INTERLEAVED)
fprintf(stderr," AVI is interleaved\n");
if(ac->total_frames)
fprintf(stderr," total frames: %d\n",
ac->total_frames);
fprintf(stderr," number of streams: %d\n",
ac->nstreams);
fprintf(stderr," size: %dx%d\n",
ac->width, ac->height);
#endif
break;
case TAG_IT('s','t','r','h'):
size = getsize(fd);
#ifdef DEBUG
fprintf(stderr," size: %d\n",size);
#endif
c=0;
read(fd,buf,size);
tag = getle32(buf);
c+=16;
#ifdef DEBUG
cc = (char *) &tag;
fprintf(stderr," tag: %c%c%c%c ",*cc,
*(cc+1),*(cc+2),*(cc+3));
#endif
switch ( tag ){
case TAG_IT('v','i','d','s'):
ac->vhandler = getle32(buf+4);
#ifdef DEBUG
if (ac->vhandler){
cc = (char *) &ac->vhandler;
fprintf(stderr," video handler: %c%c%c%c "
,*cc,*(cc+1),*(cc+2),*(cc+3));
}
#endif
ac->vi.initial_frames = getle32(buf+c);
c+=4;
ac->vi.dw_scale = getle32(buf+c);
c+=4;
ac->vi.dw_rate = getle32(buf+c);
c+=4;
ac->vi.dw_start = getle32(buf+c);
c+=4;
if (ac->vi.dw_scale)
ac->vi.fps = (ac->vi.dw_rate*1000)/
ac->vi.dw_scale;
#ifdef DEBUG
fprintf(stderr,"\n");
#endif
fprintf(stderr,"AVI video info: ");
fprintf(stderr,"dw_scale %d dw_rate %d ",
ac->vi.dw_scale, ac->vi.dw_rate);
fprintf(stderr,"fps %0.3f ini_frames %d dw_start %d\n",
ac->vi.fps/1000.0,
ac->vi.initial_frames,
ac->vi.dw_start);
break;
case TAG_IT('a','u','d','s'):
ac->ahandler = getle32(buf+4);
#ifdef DEBUG
if (ac->vhandler){
cc = (char *) &ac->ahandler;
fprintf(stderr," audio handler: %c%c%c%c "
,*cc,*(cc+1),*(cc+2),*(cc+3));
}
#endif
if (ac->ntracks == MAX_TRACK) break;
n = ac->ntracks;
ac->ai[n].initial_frames = getle32(buf+c);
c+=4;
ac->ai[n].dw_scale = getle32(buf+c);
c+=4;
ac->ai[n].dw_rate = getle32(buf+c);
c+=4;
ac->ai[n].dw_start = getle32(buf+c);
c+=16;
ac->ai[n].dw_ssize = getle32(buf+c);
if (ac->ai[n].dw_scale)
ac->ai[n].fps =
(ac->ai[n].dw_rate*1000)/
ac->ai[n].dw_scale;
#ifdef DEBUG
fprintf(stderr,"\n");
#endif
fprintf(stderr,"AVI audio%d info: ",n);
fprintf(stderr,"dw_scale %d dw_rate %d ",
ac->ai[n].dw_scale, ac->ai[n].dw_rate);
fprintf(stderr,"ini_frames %d dw_start %d",
ac->ai[n].initial_frames,
ac->ai[n].dw_start);
fprintf(stderr," fps %0.3f sam_size %d\n",
ac->ai[n].fps/1000.,
ac->ai[n].dw_ssize);
ac->ntracks++;
break;
}
break;
case TAG_IT('I','N','F','O'):
size -=4;
skip =1;
#ifdef DEBUG
fprintf(stderr," size: %d",size);
#endif
break;
}
#ifdef DEBUG
fprintf(stderr,"\n");
#endif
if (skip){
lseek(fd, size, SEEK_CUR);
size = 0;
}
}
return -1;
}
#define MAX_BUF_SIZE 0xffff
int get_avi_from_index(pes_in_t *p, int fd, avi_context *ac,
void (*func)(pes_in_t *p), int insize)
{
struct replex *rx= (struct replex *) p->priv;
avi_index *idx = ac->idx;
int cidx = ac->current_idx;
uint8_t buf[MAX_BUF_SIZE];
uint32_t cid;
int c=0;
off_t pos=0;
int per = 0;
static int lastper=0;
if (cidx > ac->num_idx_frames) return -2;
switch(idx[cidx].id){
case TAG_IT('0','1','w','b'):
p->type = 1;
p->rbuf = &rx->arbuffer[0];
break;
case TAG_IT('0','0','d','c'):
p->type = 0xE0;
p->rbuf = &rx->vrbuffer;
break;
default:
fprintf(stderr,"strange chunk :\n");
show_buf((uint8_t *) &idx[cidx].id,4);
fprintf(stderr,"offset: 0x%04x length: 0x%04x\n",
(int)idx[cidx].off, (int)idx[cidx].len);
ac->current_idx++;
p->found=0;
return 0;
break;
}
memset(buf, 0, MAX_BUF_SIZE);
pos=lseek (fd, idx[cidx].off+ac->movi_start-4, SEEK_SET);
read(fd,buf,idx[cidx].len);
cid = getle32(buf);
c+=4;
p->plength = getsize_buf(buf+c);
// show_buf(buf,16);
if (idx[cidx].len > insize) return 0;
if (idx[cidx].len > MAX_BUF_SIZE){
fprintf(stderr,"Buffer too small in get_avi_from_index\n");
exit(1);
}
if (!idx[cidx].len){
func(p);
ac->current_idx++;
p->found=0;
return 0;
}
if (cid != idx[cidx].id){
char *cc;
cc = (char *)&idx[cidx].id;
fprintf(stderr,"wrong chunk id: %c%c%c%c != %c%c%c%c\n",
buf[0],buf[1],buf[2],buf[3]
,*cc,*(cc+1),*(cc+2),*(cc+3));
print_index(ac,cidx);
exit(1);
}
if (p->plength != idx[cidx].len){
fprintf(stderr,"wrong chunk size: %d != %d\n",
(int)p->plength, idx[cidx].len);
exit(1);
}
c+=4;
p->done = 1;
p->ini_pos = ring_wpos(p->rbuf);
per = (int)(100*(pos-ac->movi_start)/ac->movi_length);
if (per>lastper) fprintf(stderr,"read %3d%%\r", per);
lastper = per;
if (ring_write(p->rbuf, buf+c, p->plength)<0){
fprintf(stderr, "ring buffer overflow %d 0x%02x\n"
,p->rbuf->size,p->type);
exit(1);
}
func(p);
init_pes_in(p, 0, NULL, p->withbuf);
ac->current_idx++;
return 0;
}
void get_avi(pes_in_t *p, uint8_t *buf, int count, void (*func)(pes_in_t *p))
{
int l;
int c=0;
struct replex *rx= (struct replex *) p->priv;
// show_buf(buf,16);
while (c < count && p->found < 8
&& !p->done){
switch ( p->found ){
case 0:
if (buf[c] == '0') p->found++;
else p->found = 0;
c++;
break;
case 1:
if (buf[c] == '0'|| buf[c] == '1'){
p->found++;
p->which = buf[c] - '0';
} else if (buf[c] == '0'){
p->found = 1;
} else p->found = 0;
c++;
break;
case 2:
switch(buf[c]){
case 'w':
case 'd':
p->found++;
p->type=buf[c];
break;
default:
p->found = 0;
break;
}
c++;
break;
case 3:
switch(buf[c]){
case 'b':
if (p->type == 'w'){
p->found++;
p->type = 1;
} else p->found = 0;
break;
case 'c':
if (p->type == 'd'){
p->found++;
p->type = 0xE0;
} else p->found = 0;
break;
default:
p->found = 0;
break;
}
switch(p->type){
case 1:
p->rbuf = &rx->arbuffer[0];
break;
case 0xE0:
p->rbuf = &rx->vrbuffer;
break;
}
c++;
break;
case 4:
p->plen[0] = buf[c];
c++;
p->found++;
break;
case 5:
p->plen[1] = buf[c];
c++;
p->found++;
break;
case 6:
p->plen[2] = buf[c];
c++;
p->found++;
break;
case 7:
p->plen[3] = buf[c];
c++;
p->found++;
p->plength = getsize_buf(p->plen);
if (!p->plength){
func(p);
p->found=0;
break;
}
p->done = 1;
p->ini_pos = ring_wpos(p->rbuf);
/*
if (p->type == 1) fprintf(stderr,"audio 0x%x 0x%x\n",
p->plength,ALIGN(p->plength));
if (p->type == 1) fprintf(stderr,"video 0x%x 0x%x\n",
p->plength,ALIGN(p->plength));
*/
break;
default:
break;
}
}
if (p->done || p->found > 8){
while (c < count && p->found < p->plength+8){
l = count -c;
if (l+p->found > p->plength+8)
l = p->plength+8-p->found;
if (ring_write(p->rbuf, buf+c, l)<0){
fprintf(stderr, "ring buffer overflow %d\n"
,p->rbuf->size);
exit(1);
}
p->found += l;
c += l;
}
if(p->found == p->plength+8){
func(p);
}
}
if (p->plength && p->found == p->plength+8) {
int a = 0;//ALIGN(p->plength);
init_pes_in(p, 0, NULL, p->withbuf);
if (c+a < count)
get_avi(p, buf+c+a, count-c-a, func);
}
}
Jump to Line
Something went wrong with that request. Please try again.