Mailing List archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Alpha Version of an avpes2mpeg Conversion Utility
[ The following text is in the "UNKNOWN-8BIT" character set. ]
[ Your display is set for the "ISO-8859-1" character set. ]
[ Some characters may be displayed incorrectly. ]
Hi,
Here is a little utility which converts an avpes stream to mpeg2 system
stream. I am releasing it under GPL, any improvements are welcome.
It is a bit too complex (and suffers from a lot of misunderstanding of
mpeg2 system streams on my side), but the results seem to be fairly ok.
Usage:
avpes2mpeg <avpesfile >mpegfile
or
avpes2mpeg start_hr start_min start_sec <avpesfile >mpegfile
(The starttime is the video time, taken from GOPs)
Since it doesn´t use seeks, you can also use it to directly record mpeg2:
avpes2mpeg </dev/video >mpegfile
Todo:
- Clean it up
- Support for cutting (at least at GOPs, with a little help from external
programs maybe even at picture level)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
unsigned int start_hr, start_min, start_sec;
unsigned int valid=0;
#define DEBUG_AVPES_SYNC 0x0001
#define DEBUG_APES_SYNC 0x0002
#define DEBUG_VPES_SYNC 0x0004
#define DEBUG_AUDIO_SYNC 0x0008
#define DEBUG_VIDEO_SYNC 0x0010
#define DEBUG_SYNC 0x00ff
#define DEBUG_AVPES_HEADER 0x0100
#define DEBUG_APES_HEADER 0x0200
#define DEBUG_VPES_HEADER 0x0400
#define DEBUG_AUDIO_HEADER 0x0800
#define DEBUG_VIDEO_HEADER 0x1000
#define DEBUG_ALL -1
int debug=DEBUG_SYNC;
#define TS_CLOCK 90000 /* Timestamp Clock Frequency */
static unsigned int bitrate_index [3][16] =
{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
static double frequency_index [4] = {44.1, 48, 32, 0};
static unsigned int slots [4] = {12, 144, 0, 0};
static unsigned int samples [4] = {384, 1152, 0, 0};
#define BUFFSIZE 2048
unsigned long long init_time;
struct buffer {
char buffer[BUFFSIZE];
int wpos;
int init;
int acu_time;
int pesh_pos;
unsigned long long time;
unsigned long long written;
} video,audio;
unsigned long long
pts2time(unsigned char *pts)
{
unsigned long long time;
unsigned char t0;
unsigned short t1,t2;
t0=pts[0];
t1=(pts[1] << 8) | pts[2];
t2=(pts[3] << 8) | pts[4];
time=(t0 >> 1) & 0x7;
time <<= 15;
time |= t1 >> 1;
time <<= 15;
time |= t2 >> 1;
return time;
}
void
time2pts(unsigned long long time, char *pts)
{
unsigned char t0;
unsigned short t1,t2;
t2=(time << 1) | 1;
time >>= 15;
t1=(time << 1) | 1;
time >>= 15;
t0=((time & 0x7)<< 1) | 0x21;
pts[0]=t0;
pts[1]=t1 >> 8;
pts[2]=t1 & 0xff;
pts[3]=t2 >> 8;
pts[4]=t2 & 0xff;
}
void
time2hhmmssff(unsigned long long time)
{
unsigned long frm_time=time/(TS_CLOCK/25);
int hr,min,sec,frm;
frm=frm_time % 25;
frm_time/=25;
sec=frm_time % 60;
frm_time/=60;
min=frm_time % 60;
frm_time/=60;
hr=frm_time;
fprintf(stderr,"%02d:%02d:%02d.%02d\n", hr, min, sec, frm);
}
void
packet_header_write(struct buffer *buff)
{
char *header=buff->buffer+buff->wpos;
char *ptr=header;
*ptr++=0;
*ptr++=0;
*ptr++=1;
*ptr++=0xba;
*ptr++=0;
*ptr++=0;
*ptr++=0;
*ptr++=0;
*ptr++=0;
*ptr++=0;
*ptr++=0x01;
*ptr++=0x89;
*ptr++=0xc3;
*ptr++=0xf8;
buff->wpos+=ptr-header;
}
void
packet_header_update(struct buffer *buff)
{
#if 1
static unsigned long scr;
#else
static unsigned long scr=1;
#endif
unsigned long tmp1;
unsigned short tmp2;
char *header=buff->buffer+buff->wpos;
char *ptr=header;
ptr+=4; /* skip 0x00 0x00 0x01 0xba */
/* Clock Ref 3 + 4 + 4 + 4 + 3 + 4 + 1
10XX 0XXX XXXX XXXX XXXX 0XXX XXXX X0YY YYYY YYYY0
*/
tmp1=0x40000000 |
((scr >> 3) & 0x30000000) |
((scr >> 4) & 0x03fff800) |
((scr >> 5) & 0x000003ff);
tmp2=(scr << 11) & 0xf800;
#if 1
scr+=146;
#else
scr <<=1;
#endif
*ptr++=tmp1 >> 24;
*ptr++=tmp1 >> 16;
*ptr++=tmp1 >> 8;
*ptr++=tmp1;
*ptr++=tmp2 >> 8;
*ptr++=tmp2;
}
void
system_header_write(struct buffer *buff)
{
char header[]={ 0x00,0x00,0x01,0xbb,0x00,0x12,0x80,0xc4,0xe1,0x04,0xe1,
0x7f,0xe0,0xe0,0xe8,0xc0,0xc0,0x20,0xbd,0xe0,0x3a,0xbf,0xe0,0x02};
memcpy(buff->buffer+buff->wpos, header, sizeof(header));
buff->wpos+=sizeof(header);
}
void
pes_header_write(int chan, struct buffer *buff, int len,
unsigned long long pt, unsigned long long dt)
{
char *ptri,*ptr;
char pts_buf[5];
#if 0
fprintf(stderr,"pes_header_write %x, %Ld, %Ld\n", chan, pt, dt);
#endif
ptr=buff->buffer+buff->wpos;
buff->pesh_pos=buff->wpos;
ptri=ptr;
*ptr++=0;
*ptr++=0;
*ptr++=1;
*ptr++=chan;
*ptr++=len >> 8;
*ptr++=len;
*ptr++=0x81;
*ptr++=((pt != -1)?0x80:0x00)|((dt != -1)?0x40:0x00);
*ptr++=((pt != -1)?5:0)+((dt != -1)?5:0);
if (pt != -1) {
time2pts(pt, pts_buf);
*ptr++=pts_buf[0];
*ptr++=pts_buf[1];
*ptr++=pts_buf[2];
*ptr++=pts_buf[3];
*ptr++=pts_buf[4];
}
if (dt != -1) {
time2pts(dt, pts_buf);
*ptr++=pts_buf[0];
*ptr++=pts_buf[1];
*ptr++=pts_buf[2];
*ptr++=pts_buf[3];
*ptr++=pts_buf[4];
}
buff->wpos+=ptr-ptri;
}
void
pes_header_update(struct buffer *buff, int len)
{
char *ptr;
if (! buff->pesh_pos)
return;
ptr=buff->buffer+buff->pesh_pos;
ptr[4]=len >> 8;
ptr[5]=len;
}
unsigned long long pad_written;
void
pes_pad(struct buffer *buff, int len)
{
char *ptr,*ptri;
ptr=buff->buffer+buff->wpos;
ptri=ptr;
len-=6;
pad_written+=len;
*ptr++=0;
*ptr++=0;
*ptr++=1;
*ptr++=0xbe;
*ptr++=len >> 8;
*ptr++=len;
while (len-- > 0) {
*ptr++=0xff;
}
buff->wpos+=ptr-ptri;
}
void
buffer_write(struct buffer *buff)
{
buff->wpos=0;
packet_header_update(buff);
write(1, buff->buffer, BUFFSIZE);
}
void
new_acu(int chan, unsigned long long pt, unsigned long long dt, int force)
{
struct buffer *buff;
int diff;
#if 0
fprintf(stderr, "ACU %x %Ld %Ld %d\n", chan, pt, dt, force);
#endif
#if 0
if (! init_time)
init_time=pt-1;
#endif
#if 0
fprintf(stderr, "ACU: time %d\n", pt-init_time);
#endif
if (chan >=0xe0)
buff=&video;
else {
buff=&audio;
if ((!buff->pesh_pos && !init_time) || pt < init_time) {
return ;
}
}
diff=BUFFSIZE-buff->wpos;
if ((diff < 256 || !buff->pesh_pos || force) && diff > 8) {
if (buff->pesh_pos) {
pes_header_update(buff, buff->wpos-buff->pesh_pos-6);
pes_pad(buff, diff);
buffer_write(buff);
}
if (force && !init_time)
init_time=pt-1;
buff->acu_time=0;
packet_header_write(buff);
if (pt != -1) {
if (pt <= init_time)
pt=1;
else
pt-=init_time;
}
if (dt != -1) {
if (dt <= init_time)
dt=1;
else
dt-=init_time;
}
pes_header_write(chan, buff, BUFFSIZE-buff->wpos-6, pt, dt);
}
#if 0
else
fprintf(stderr, "SKIP_ACU %x\n", chan);
#endif
}
void
do_write(int chan, char *addr, int len)
{
int free,to_write;
struct buffer *buff;
if (chan >=0xe0)
buff=&video;
else
buff=&audio;
if (! buff->pesh_pos) {
#if 0
fprintf(stderr, "Write skip %x\n", chan);
#endif
return;
}
buff->written+=len;
while (len) {
free=BUFFSIZE-buff->wpos;
to_write=len;
if (to_write > free)
to_write=free;
memcpy(buff->buffer+buff->wpos, addr, to_write);
buff->wpos+=to_write;
len-=to_write;
addr+=to_write;
if (buff->wpos == BUFFSIZE) {
buffer_write(buff);
packet_header_write(buff);
pes_header_write(chan, buff, BUFFSIZE-buff->wpos-6, -1, -1);
}
}
}
void
mpeg2_video_write(unsigned char *buffer, int len, unsigned long pts)
{
static int state=0;
int i;
#if 0
fprintf(stderr,"VIDEO: buffer %x len %d\n", buffer, len);
#endif
while (len) {
switch(state) {
case 0:
len--;
if (*buffer++ == 0)
state=1;
break;
case 1:
len--;
if (*buffer++ == 0)
state=2;
else
state=0;
break;
case 2:
len--;
if (*buffer++ == 1)
state=3;
else
state=0;
break;
case 3:
len--;
if (*buffer++ == 0xb3 && pts) {
char header[4]={0x00,0x00,0x01,0xb3};
if (valid) {
int goppos=-1;
for (i = 0 ; i < len-3 ; i++) {
if (buffer[i] == 0x0 && buffer[i+1] == 0x0 && buffer[i+2] == 0x1 && buffer[i+3] == 0xb8) {
goppos=i;
break;
}
}
if (goppos != -1 ) {
unsigned long x;
unsigned int hr,min,sec,frame;
x=(buffer[goppos+4] << 24) | (buffer[goppos+5] << 16) |
(buffer[goppos+6] << 8) | buffer[goppos+7];
hr=(x >> 26) & 0x1f;
min=(x >> 20) & 0x3f;
sec=(x >> 13) & 0x3f;
frame=(x >> 7) & 0x3f;
fprintf(stderr,"%02d:%02d:%02d.%02d\n",hr,min,sec,frame);
if (hr != start_hr || min != start_min || sec != start_sec) {
state=0;
break;
}
else
fprintf(stderr, "Start found\n");
}
else {
fprintf(stderr, "no GOP %x %x %x %x\n", buffer[158], buffer[159], buffer[160], buffer[161]);
state=0;
break;
}
}
new_acu(0xe0, pts, pts-10800, 1);
do_write(0xe0, header, 4);
state=4;
}
else
state=0;
break;
case 4:
if (pts && len > 7) {
for (i = 0 ; i < len-4 ; i++) {
if (buffer[i+0] == 0 && buffer[i+1] == 0 && buffer[i+2] == 1
&& buffer[i+3] == 0xb3) {
if (i) {
do_write(0xe0, buffer, i);
buffer+=i;
len-=i;
}
new_acu(0xe0, pts, pts-10800, 1);
break;
}
}
}
do_write(0xe0, buffer, len);
buffer+=len;
len=0;
break;
}
}
}
void
mpeg2_audio_write(unsigned char *buffer, int len)
{
static int state=0;
static int skiph=0,skipb=0,skip=0,plen=0,flen=0;
int to_go=0;
static unsigned char header[32];
if (debug & DEBUG_APES_HEADER) {
fprintf(stderr, "APES: New Block with len %d\n", len);
}
while (len) {
header[state]=*buffer;
switch(state) {
case 0: /* 00 */
len--;
if (*buffer++ == 0)
state=1;
else {
if (debug & DEBUG_APES_SYNC) {
if (! skiph)
fprintf(stderr, "APES: Syncing Header... ");
skiph++;
}
}
break;
case 1: /* 00 */
len--;
if (*buffer++ == 0)
state=2;
else {
if (debug & DEBUG_APES_SYNC) {
if (! skiph)
fprintf(stderr, "APES: Syncing Header... ");
skiph++;
}
state=0;
}
break;
case 2: /* 01 */
len--;
if (*buffer++ == 1)
state=3;
else {
if (debug & DEBUG_APES_SYNC) {
if (! skiph)
fprintf(stderr, "APES: Syncing Header... ");
skiph++;
}
state=0;
}
break;
case 3: /* cx/dx */
len--;
if (*buffer >= 0xc0 && *buffer < 0xe0) {
buffer++;
state=4;
}
else {
if (debug & DEBUG_APES_SYNC) {
if (! skiph)
fprintf(stderr, "APES: Syncing Header... ");
skiph++;
}
buffer++;
state=0;
}
break;
case 4: /* lenh */
if (debug & DEBUG_APES_SYNC) {
if (skiph) {
fprintf(stderr, "%d APES bytes skipped\n", skiph);
skiph=0;
}
}
len--;
plen=(*buffer++) << 8;
state=5;
break;
case 5: /* lenl */
len--;
plen|=*buffer++;
skip=8;
state=6;
break;
case 6: /* 10 PSC PESP DAI CY OOCF */
case 7: /* PTSF DTSF ESCRF ESRF DSMTMF ACIF PESCRCF PESHDL */
case 8: /* Header Length */
case 9: /* PTS */
case 10:
case 11:
case 12:
len--;
plen--;
buffer++;
state++;
break;
case 13: /* PTS Ende */
len--;
plen--;
buffer++;
state++;
audio.time=pts2time(header+9);
if (debug & DEBUG_APES_HEADER) {
fprintf(stderr,"APES: Header Magic:0x%02x 0x%02x 0x%02x 0x%02x",
header[0], header[1], header[2], header[3]);
fprintf(stderr," len:%d flags:0x%02x 0x%02x hlen:%d pts:%Ld\n",
(header[4] << 8) | header[5], header[6], header[7],
header[8], audio.time);
}
break;
case 14: /* MPEG Audio Header */
len--;
plen--;
if (*buffer++ == 0xff) {
if (skipb) {
fprintf(stderr, "Audio: Skip1: Skipped %d bytes\n", skipb);
skipb=0;
}
state++;
}
else {
if (! skipb) {
fprintf(stderr, "Audio: Skip1 %x != 0xff len %d\n",buffer[-1],plen);
}
skipb++;
if (plen <= 0)
state=0;
}
break;
case 15:
len--;
plen--;
if ((*buffer++ & 0xf0) == 0xf0)
state++;
else {
fprintf(stderr, "Audio: Skip2\n");
if (plen <= 0)
state=0;
else
state=14;
}
break;
case 16:
len--;
plen--;
buffer++;
state++;
break;
case 17: /* MPEG Audio Header End */
len--;
plen--;
buffer++;
state++;
new_acu(0xc0, audio.time, -1, 0);
do_write(0xc0, header+14, 4);
{
unsigned int sync_word;
unsigned int layer;
unsigned int protection;
unsigned int bit_rate;
unsigned int frequency;
unsigned int padding;
unsigned int mode;
unsigned int mode_extension;
unsigned int copyright;
unsigned int original_copy;
unsigned int emphasis;
unsigned int framesize;
sync_word=(header[14] << 8) | header[15];
if ((sync_word & 0xfff0) != 0xfff0) {
fprintf(stderr, "Audio: Out of Sync %x len %d\n",
sync_word, plen);
}
layer=(sync_word >> 1) &3;
protection=sync_word & 0x1;
bit_rate=(header[16] >> 4) & 0xf;
frequency=(header[16] >> 2) & 0x3;
padding=(header[16] >> 1) & 0x1;
mode=(header[17] >> 6) & 0x3;
mode_extension=(header[17] >> 4) & 0x3;
copyright=(header[17] >> 3) & 0x1;
original_copy=(header[17] >> 2) & 0x1;
emphasis=header[17] & 0x3;
framesize=bitrate_index[3-layer][bit_rate] /
frequency_index[frequency] * slots [3-layer];
#if 0
fprintf(stderr, "framesize %d plen %d len %d\n",
framesize,plen,len);
#endif
flen=framesize-4;
audio.time+=TS_CLOCK*samples[3-layer]/
(frequency_index[frequency]*1000);
}
break;
case 18:
to_go=flen;
if (to_go > len)
to_go=len;
do_write(0xc0, buffer, to_go);
len -= to_go;
buffer += to_go;
plen -= to_go;
flen -= to_go;
if (! flen)
state=14;
if (plen <= 0)
state=0;
break;
}
}
}
void
avpes_read(unsigned char *buffer, int len)
{
static int state=0;
static unsigned char header[32];
static int gap1,plen;
static int to_write;
static int sync=0;
int curr;
unsigned long long pts=0;
while (len) {
header[state]=*buffer;
switch(state) {
case 0: /* 0x41 */
len--;
if (*buffer++ == 0x41)
state=1;
else {
if (debug & DEBUG_AVPES_SYNC) {
if (! sync)
fprintf(stderr, "AVPES: Syncing Header... ");
sync++;
}
}
break;
case 1: /* 0x56 */
len--;
if (*buffer++ == 0x56)
state=2;
else
state=0;
break;
case 2: /* type */
len--;
buffer++;
state=3;
break;
case 3: /* sequence */
len--;
buffer++;
state=4;
break;
case 4: /* 0x55 */
len--;
if (*buffer++ == 0x55)
state=5;
else
state=0;
break;
case 5: /* gap */
case 6: /* lenhi */
case 7: /* lenlo */
len--;
buffer++;
state++;
break;
case 8:
if (debug & DEBUG_AVPES_SYNC) {
if (sync)
fprintf(stderr, "%d AVPES bytes skipped\n",sync);
sync=0;
}
gap1=(header[5] >> 2) & 0x3;
plen=header[6]*256+header[7];
gap1=0;
if (debug & DEBUG_AVPES_HEADER) {
fprintf(stderr, "AVPES: Header Magic:0x%02x 0x%02x Type:0x%02x",
header[0], header[1], header[2]);
fprintf(stderr, " Sequence:0x%02x Magic:0x%02x Gap:0x%02x Len:%d",
header[3], header[4], header[5], plen);
}
state=9;
break;
case 9:
pts=0;
if (header[5] & 0x10) {
if (header[2]==2) {
if (debug & DEBUG_AVPES_HEADER) {
fprintf(stderr, " NO PTS FOR AUDIO");
}
to_write=plen-gap1;
state=14;
break;
}
state=10;
} else {
to_write=plen-gap1;
state=14;
}
break;
case 10: /* pts 1 */
case 11: /* pts 2 */
case 12: /* pts 3 */
plen--;
len--;
buffer++;
state++;
break;
case 13: /* pts 4 */
plen--;
len--;
buffer++;
state++;
pts=(header[10] << 24) |
(header[11] << 16) |
(header[12] << 8) |
header[13];
to_write=plen-gap1;
break;
case 14:
if (debug & DEBUG_AVPES_HEADER) {
if (pts)
fprintf(stderr," PTS:%Ld\n", pts);
else
fprintf(stderr,"\n");
}
curr=to_write;
if (curr > len)
curr=len;
if (header[2] == 1)
mpeg2_video_write(buffer, curr, pts);
if (header[2] == 2)
mpeg2_audio_write(buffer, curr);
buffer+=curr;
len-=curr;
plen-=curr;
to_write-=curr;
if (! to_write)
state=15;
break;
case 15:
if (len >= gap1) {
len-=gap1;
buffer+=gap1;
gap1=0;
state=0;
}
else {
gap1-=len;
buffer+=len;
len=0;
}
break;
}
}
}
unsigned long long av_read;
unsigned long last;
int
main(int argc, char **argv)
{
#define BUFFER_SIZE 65536*4
unsigned char buffer[BUFFER_SIZE];
int len;
if (argc > 3) {
start_hr=atoi(argv[1]);
start_min=atoi(argv[2]);
start_sec=atoi(argv[3]);
valid=1;
}
while ( (len=read(0, buffer, BUFFER_SIZE)) ) {
av_read+=len;
last+=len;
if (last >= 10*1024*1024) {
last=0;
fprintf(stderr,"AVPES: %Ld MB read VIDEO: %Ld MB AUDIO: %Ld MB PAD: %Ld MB written\n",
av_read/1024/1024, video.written/1024/1024,
audio.written/1024/1024, pad_written/1024/1024);
}
avpes_read(buffer, len);
}
return(0);
}
--
Martin (martin@smurf.franken.de)
Home |
Main Index |
Thread Index