You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
k9copy/k9vamps/k9vamps.cpp

1101 lines
28 KiB

//
// C++ Interface: k9vamps
//
// Description: A transcription from Vamps in C++
//
//
// Author: Jean-Michel PETIT <k9copy@free.fr>, (C) 2006
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "k9vamps.h"
#include <tqapplication.h>
#include "ac.h"
void k9vamps::setNoData() {
noData=true;
wDataRead.wakeAll();
wDataReady.wakeAll();
}
void k9vamps::addData(uchar *data,uint size) {
while (1) {
if (m_fifo.freespace()>=size) {
m_fifo.enqueue(data,size);
wDataReady.wakeAll();
break;
} else
wDataRead.wait();
}
}
int k9vamps::readData(uchar * data,uint size) {
uint size2=size;
uint32_t readSize=0,s=0;
while (1) {
// is there data in the buffer?
if (m_fifo.count() >0) {
// s= size of data that we will read (maximum = size)
s=(m_fifo.count()) <size2 ? (m_fifo.count()) : size2;
// increments the number of readen bytes
readSize+=s;
// decrements the number of max bytes to read
size2-=s;
//moves bytes from buffer to output
m_fifo.dequeue(data,s);
//moves the position of output buffer to receive next bytes
data+=s;
//there's now free space in input buffer, we can wake the injection thread
wDataRead.wakeAll();
}
// break the loop if injection thread terminated or we got what we want (size bytes)
// otherwise, we're waiting for datas
if(noData || (m_fifo.count() >=size2)) {
break;
} else
wDataReady.wait();
}
// if there's datas in input buffer and we did not get all what we wanted, we take them.
s= (m_fifo.count()) <size2 ? (m_fifo.count()) : size2;
readSize+=s;
if (s>0 )
m_fifo.dequeue(data,s);
wDataRead.wakeAll();
return readSize;
}
void k9vamps::addSubpicture(uint id) {
int cpt=1;
for (uint i=0;i<32;i++)
if (spu_track_map[i]!=0) cpt++;
spu_track_map[id-1]=cpt;
}
void k9vamps::addAudio(uint id) {
int cpt=1;
for (uint i=0;i <8;i++)
if (audio_track_map[i] !=0) cpt++;
audio_track_map[id-1]=cpt;
}
void k9vamps::addAudio(uint id,uint newId) {
if (newId==0)
addAudio(id);
else
audio_track_map[id-1]=newId;
}
void k9vamps::setInputSize(uint64_t size) {
ps_size=size;
}
void k9vamps::setVapFactor(float factor) {
vap_fact=factor;
}
void k9vamps::setSaveImage(k9SaveImage *m_save) {
m_saveImage=m_save;
}
void k9vamps::reset() {
m_preserve=true;
bytes_read =0;
bytes_written=0;
padding_bytes=0;
total_packs=0;
video_packs=0;
skipped_video_packs=0;
aux_packs=0;
skipped_aux_packs=0;
sequence_headers=0;
nav_packs=0;
rptr = rbuf;
rhwp = rbuf;
wptr = wbuf;
vbuf_size = VBUF_SIZE;
vap_fact= 1.0f;
// inbuffw=inbuff;
for (uint i=0; i<8;i++) {
audio_track_map[i]=0;
}
for (uint i=0; i<32;i++) {
spu_track_map[i]=0;
}
calc_ps_vap = 1;
vap_fact=1.0;
ps_size=0;
noData=false;
avgdiff=1;
m_totfact=m_nbfact=m_avgfact=0;
vin_bytes=0;
vout_bytes=0;
}
k9vamps::k9vamps(k9DVDBackup *dvdbackup) {
m_saveImage=NULL;
m_dvdbackup=dvdbackup;
reset();
m_requant=NULL;
if (dvdbackup !=NULL)
m_bgUpdate = new k9bgUpdate(dvdbackup);
else
m_bgUpdate=NULL;
rbuf_size= RBUF_SIZE;
rbuf = (uchar*) malloc(rbuf_size);;
m_output=NULL;
}
void k9vamps::setPreserve(bool _value) {
m_preserve = _value;
}
void k9vamps::setOutput(TQFile *_output) {
m_output=_output;
}
k9vamps::~k9vamps() {
if (m_bgUpdate !=NULL)
delete m_bgUpdate;
free (rbuf);
}
void k9vamps::run () {
m_error=false;
m_errMsg="";
m_requant=new k9requant();
eof=0;
// allocate video buffers
vibuf =(uchar*) malloc (vbuf_size);
vobuf = (uchar*) malloc (vbuf_size);
if (vibuf == NULL || vobuf == NULL)
fatal (TQString("Allocation of video buffers failed: %1").arg(strerror (errno)));
// actually do vaporization
vaporize ();
flush();
if (m_requant !=NULL) {
m_requant->rqt_stop=true;
while(m_requant->running()) {
m_requant->condr.wakeAll();
m_requant->condw.wakeAll();
m_requant->wait(10);
}
// m_requant->mutr.unlock();
// m_requant->mutw.unlock();
}
delete m_requant;
m_requant=NULL;
free (vibuf);
free(vobuf);
if (m_bgUpdate!=NULL)
m_bgUpdate->wait();
//mutex.unlock();
}
// lock `size' bytes in read buffer
// i.e. ensure the next `size' input bytes are available in buffer
// returns nonzero on EOF
int k9vamps::lock (int size) {
int avail, n;
avail = rhwp - rptr;
if (avail >= size)
return 0;
if (avail) {
tc_memcpy (rbuf, rptr, avail);
rptr = rbuf;
rhwp = rptr + avail;
}
if (rbuf_size -avail <=0) {
uchar *buffer =(uchar*) malloc (rbuf_size+20480);
tc_memcpy (buffer,rbuf,rbuf_size);
rptr = buffer +(rptr-rbuf);
rhwp=buffer+(rhwp-rbuf);
rbuf_size+=20480;
free(rbuf);
rbuf=buffer;
}
n = readData(rhwp,rbuf_size - avail);
if (n % SECT_SIZE)
fatal ("Premature EOF");
rhwp += n;
bytes_read += n;
return !n;
}
// copy `size' bytes from rbuf to wbuf
void k9vamps::copy (int size) {
if (!size)
return;
if ((wptr - wbuf) + size > WBUF_SIZE)
fatal ("Write buffer overflow");
tc_memcpy (wptr, rptr, size);
rptr += size;
wptr += size;
}
// skip `size' bytes in rbuf
void k9vamps::skip (int size) {
rptr += size;
}
// flush wbuf
void k9vamps::flush (void) {
int size;
mutex.lock();
size = wptr - wbuf;
if (!size) {
mutex.unlock();
return;
}
//m_dvdbackup->getOutput(wbuf,size);
// wait for a preceding update to finish
if (m_bgUpdate!=NULL) {
m_bgUpdate->wait();
m_bgUpdate->update( wbuf,size);
}
if (m_output != NULL)
m_output->writeBlock((const char*) wbuf,size);
if (m_saveImage !=NULL)
m_saveImage->addData(wbuf,size);
wptr = wbuf;
bytes_written += size;
mutex.unlock();
}
// returns no. bytes read up to where `ptr' points
uint64_t k9vamps::rtell (uchar *ptr) {
return bytes_read - (rhwp - ptr);
}
// returns no. bytes written up to where `ptr' points
// (including those in buffer which are not actually written yet)
uint64_t k9vamps::wtell (uchar *ptr) {
return bytes_written + (ptr - wbuf);
}
// some pack header consistency checking
bool k9vamps::check_pack (uchar *ptr) {
uint32_t pack_start_code;
int pack_stuffing_length;
pack_start_code = (uint32_t) (ptr [0]) << 24;
pack_start_code |= (uint32_t) (ptr [1]) << 16;
pack_start_code |= (uint32_t) (ptr [2]) << 8;
pack_start_code |= (uint32_t) (ptr [3]);
if (pack_start_code != 0x000001ba) {
// fatal ("Bad pack start code at %llu: %08lx", rtell (ptr), pack_start_code);
return false;
}
if ((ptr [4] & 0xc0) != 0x40) {
// fatal ("Not an MPEG2 program stream pack at %llu", rtell (ptr));
return false;
}
// we rely on a fixed pack header size of 14
// so better to ensure this is true
pack_stuffing_length = ptr [13] & 7;
if (pack_stuffing_length) {
//fatal ("Non-zero pack stuffing length at %llu: %d\n", rtell (ptr), pack_stuffing_length);
return false;
}
return true;
}
// video packet consistency checking
int k9vamps::check_video_packet (uchar *ptr) {
int vid_packet_length, pad_packet_length, rc = 0;
uint32_t vid_packet_start_code, pad_packet_start_code, sequence_header_code;
vid_packet_start_code = (uint32_t) (ptr [0]) << 24;
vid_packet_start_code |= (uint32_t) (ptr [1]) << 16;
vid_packet_start_code |= (uint32_t) (ptr [2]) << 8;
vid_packet_start_code |= (uint32_t) (ptr [3]);
if (vid_packet_start_code != 0x000001e0)
fatal(TQString ("Bad video packet start code at %1: %2").arg(rtell(ptr)).arg(vid_packet_start_code,0,16));
vid_packet_length = ptr [4] << 8;
vid_packet_length |= ptr [5];
vid_packet_length += 6;
if ((ptr [6] & 0xc0) != 0x80)
fatal (TQString("Not an MPEG2 video packet at %1").arg(rtell (ptr)));
if (ptr [7]) {
if ((ptr [7] & 0xc0) != 0xc0)
tqDebug ("%s", (TQString("First video packet in sequence starting at %1 misses PTS or DTS, flags=%2").arg(rtell (ptr)).arg(ptr [7])).ascii());
else {
sequence_header_code = (uint32_t) (ptr [6 + 3 + ptr [8] + 0]) << 24;
sequence_header_code |= (uint32_t) (ptr [6 + 3 + ptr [8] + 1]) << 16;
sequence_header_code |= (uint32_t) (ptr [6 + 3 + ptr [8] + 2]) << 8;
sequence_header_code |= (uint32_t) (ptr [6 + 3 + ptr [8] + 3]);
if (sequence_header_code == 0x000001b3) {
rc = 1;
} else {
//fprintf (stderr, "Start of GOP at %llu not on sector boundary\n",
// rtell (ptr + 6 + 3 + ptr [8]));
sequence_headers++;
}
}
}
pad_packet_length = 0;
if (14 + vid_packet_length < SECT_SIZE - 6) {
// video packet does not fill whole sector
// check for padding packet
ptr += vid_packet_length;
pad_packet_start_code = (uint32_t) (ptr [0]) << 24;
pad_packet_start_code |= (uint32_t) (ptr [1]) << 16;
pad_packet_start_code |= (uint32_t) (ptr [2]) << 8;
pad_packet_start_code |= (uint32_t) (ptr [3]);
if (pad_packet_start_code != 0x000001be)
tqDebug (TQString("Bad padding packet start code at %1: %2").arg(rtell (ptr + vid_packet_length)).arg(pad_packet_start_code));
else {
pad_packet_length = ptr [4] << 8;
pad_packet_length |= ptr [5];
pad_packet_length += 6;
}
}
// length of video packet plus padding packet must always match sector size
if (14 + vid_packet_length + pad_packet_length != SECT_SIZE)
tqDebug (TQString("Bad video packet length at %1: %2").arg(rtell (ptr)).arg(vid_packet_length));
return rc;
}
// here we go
// this is where we switch to the requantization thread
// note that this and the requant thread never run concurrently (apart
// from a very short time) so a dual CPU box does not give an advantage
// returns size of evaporated GOP
int k9vamps::requant (uchar *dst, uchar *src, int n, float fact) {
if (n==0) return 0;
int rv;
if (! m_requant->running()) {
m_requant->initvar();
}
m_requant->rqt_stop=false;
// this ensures for the requant thread to stop at this GOP's end
tc_memcpy (src + n, "\0\0\1", 3);
m_requant->mutr.lock();
m_requant->rqt_rptr = src;
m_requant->rqt_wptr = dst;
m_requant->rqt_rcnt = n;
m_requant->rqt_wcnt = 0;
m_requant->rqt_fact = fact ;
m_requant->rqt_inbytes = vin_bytes;
m_requant->rqt_outbytes = vout_bytes;
m_requant->rqt_visize = (uint64_t) ((float) ps_size * (float) vin_bytes / ((float) total_packs * (float) SECT_SIZE));
// create requantization thread
if (! m_requant->running()) {
m_requant->start();
m_requant->rqt_run=true;
}
m_requant->condr.wakeAll();
m_requant->mutr.unlock();
// now the requant thread should be running
m_requant->mutw.lock();
// wait for requant thread to finish
while (!m_requant->rqt_wcnt)
m_requant->condw.wait( &m_requant->mutw);
rv = m_requant->rqt_wcnt;
m_requant->mutw.unlock();
/* if ((m_requant->rbuf-m_requant->cbuf -3) >0 ) {
tc_memcpy(dst+m_requant->rqt_wcnt,m_requant->cbuf,m_requant->rbuf-m_requant->cbuf -3);
rv +=m_requant->rbuf-m_requant->cbuf -3;
}
/*/
if ((m_requant->rbuf-m_requant->cbuf -2) >0 ) {
tc_memcpy(dst+m_requant->rqt_wcnt,m_requant->cbuf,m_requant->rbuf-m_requant->cbuf -2);
rv +=m_requant->rbuf-m_requant->cbuf -2;
}
// if (rv>n)
// tqDebug("requant error");
double realrqtfact=(double)(vin_bytes) / (double)(vout_bytes+rv);
avgdiff = ((m_avgfact) /realrqtfact);
//tqDebug ("factor : " +TQString::number(m_avgfact) +" --> " +TQString::number((float)n/(float)rv) +" avgdiff : " + TQString::number(avgdiff) +" rqt_visize :" +TQString::number(m_requant->rqt_visize) +" ps_size :" +TQString::number(ps_size) + " vin_bytes :" + TQString::number(vin_bytes)) ;
return rv;
}
// translate type of private stream 1 packet
// according to the track translation maps
// returns new track type (e.g. 0x80 for first AC3 audio
// track in cmd line) or zero if track is not to be copied
int k9vamps::new_private_1_type (uchar *ptr) {
int type, track, abase;
type = ptr [6 + 3 + ptr [8]];
//fprintf (stderr, "type=%02x\n", type);
if (type >= 0x20 && type <= 0x3f) {
// subpicture
track = spu_track_map [type - 0x20];
return track ? track - 1 + 0x20 : 0;
}
if (type >= 0x80 && type <= 0x87) {
// AC3 audio
abase = 0x80;
} else if (type >= 0x88 && type <= 0x8f) {
// DTS audio
abase = 0x88;
} else if (type >= 0xa0 && type <= 0xa7) {
// LPCM audio
abase = 0xa0;
} else {
// fatal ("Unknown private stream 1 type at %llu: %02x", rtell (ptr), type);
abase = 0;
}
track = audio_track_map [type - abase];
return track ? track - 1 + abase : 0;
}
// selectivly copy private stream 1 packs
// patches track type to reflect new track
// mapping unless user opted to preserve them
void k9vamps::copy_private_1 (uchar *ptr) {
int type;
type = new_private_1_type (ptr);
if (type) {
if (!m_preserve)
ptr [6 + 3 + ptr [8]] = type;
copy (SECT_SIZE);
return;
}
skip (SECT_SIZE);
}
// translate ID of MPEG audio packet
// according to the audio track translation map
// returns new ID (e.g. 0xc0 for first MPEG audio
// track in cmd line) or zero if track is not to be copied
int k9vamps::new_mpeg_audio_id (int id) {
int track;
track = audio_track_map [id - 0xc0];
return track ? track - 1 + 0xc0 : 0;
}
// selectivly copy MPEG audio packs
// patches ID to reflect new track mapping unless user opted to preserve them
void k9vamps::copy_mpeg_audio (uchar *ptr) {
int id;
id = new_mpeg_audio_id (ptr [3]);
if (id) {
if (!m_preserve)
ptr [3] = id;
copy (SECT_SIZE);
return;
}
skip (SECT_SIZE);
}
// process beginning of program stream up to
// - but not including - first sequence header
// this PS leader is NOT shrunk since the PS may not
// necessarily begin at a GOP boundary (although it should?)
// nevertheless the unwanted private stream 1 and MPEG audio
// packs are skipped since some players could get confused otherwise
void k9vamps::vap_leader () {
uchar *ptr;
int id, data_length;
while (!lock (SECT_SIZE)) {
ptr = rptr;
if (check_pack (ptr)) {
ptr += 14;
id = ptr [3];
} else {
ptr +=14;
id = 0;
}
switch (id) {
case 0xe0:
// video
if (check_video_packet (ptr))
// sequence header
return;
copy (SECT_SIZE);
break;
case 0xbd:
// private 1: audio/subpicture
copy_private_1 (ptr);
break;
case 0xc0:
case 0xc1:
case 0xc2:
case 0xc3:
case 0xc4:
case 0xc5:
case 0xc6:
case 0xc7:
// MPEG audio
copy_mpeg_audio (ptr);
break;
case 0xbb:
// system header/private 2: PCI/DSI
copy (SECT_SIZE);
break;
case 0xbe:
// padding
data_length = ptr [4] << 8;
data_length |= ptr [5];
if (14 + data_length != SECT_SIZE - 6)
fatal (TQString("Bad padding packet length at %1: %2").arg(rtell (ptr)).arg(data_length));
//JMP:à vérifier
skip (SECT_SIZE);
break;
default:
// fatal("Encountered stream ID %02x at %llu, "
// "probably bad MPEG2 program stream", id, rtell (ptr));
copy (SECT_SIZE);
}
if (wptr == wbuf + WBUF_SIZE)
flush ();
}
eof = 1;
flush ();
return;
}
// process end of program stream
// the same counts here as for the PS' beginning
void k9vamps::vap_trailer (int length) {
uchar *ptr;
int i, id, data_length;
for (i = 0; i < length; i += SECT_SIZE) {
ptr = rptr + 14;
id = ptr [3];
if (id == 0xbd) {
// private 1: audio/subpicture
copy_private_1 (ptr);
} else if (id >= 0xc0 && id <= 0xc7) {
// MPEG audio
copy_mpeg_audio (ptr);
} else if (id == 0xbe) {
// padding
data_length = ptr [4] << 8;
data_length |= ptr [5];
if (14 + data_length != SECT_SIZE - 6)
fatal (TQString("Bad padding packet length at %1: %2").arg(rtell (ptr)).arg(data_length));
skip (SECT_SIZE);
} else {
copy (SECT_SIZE);
}
if (wptr == wbuf + WBUF_SIZE)
flush ();
}
flush ();
}
// vaporization is split in two phases - this is phase 1
// PS packs are read into rbuf until a sequence header is found.
// All video packs are unpacketized and the contained video ES
// GOP copied to vibuf. In the same course the private stream 1
// and MPEG audio packs are inspected and the number of packs
// not to be copied are counted. This is to forecast the video
// vaporization factor in case the user specified a PS shrink factor.
// returns GOP length in bytes
int k9vamps::vap_phase1 (void) {
uchar *ptr, *viptr = vibuf;
int seq_length, id, data_length, opt_length, seqhdr;
for (seq_length = 0;
!lock (seq_length + SECT_SIZE); seq_length += SECT_SIZE) {
ptr = rptr + seq_length;
if (check_pack (ptr)) {
ptr += 14;
id = ptr [3];
} else {
ptr += 14;
id = 0;
}
// avoid duplicate counts for sequence headers
if (seq_length)
total_packs++;
switch (id) {
case 0xe0:
// video
seqhdr = check_video_packet (ptr);
if (seq_length) {
video_packs++;
if (seqhdr) {
sequence_headers++;
vilen = viptr - vibuf;
return seq_length;
}
}
// copy contained video ES fragment to vibuf
data_length = ptr [4] << 8;
data_length |= ptr [5];
opt_length = 3 + ptr [8];
data_length -= opt_length;
if ((viptr - vibuf) + data_length > vbuf_size - 3) {
// reallocate video buffers
int i = viptr - vibuf;
// grow by another VBUF_SIZE bytes
vbuf_size += VBUF_SIZE;
vibuf = (uchar*)realloc (vibuf, vbuf_size);
vobuf = (uchar*)realloc (vobuf, vbuf_size);
if (vibuf == NULL || vobuf == NULL)
fatal ("Reallocation of video buffers failed");
viptr = vibuf + i;
}
//fprintf (stderr, "data_length=%d\n", data_length);
tc_memcpy (viptr, ptr + 6 + opt_length, data_length);
viptr += data_length;
break;
case 0xbd:
// private 1: audio/subpicture
aux_packs++;
if (!new_private_1_type (ptr))
skipped_aux_packs++;
break;
case 0xc0:
case 0xc1:
case 0xc2:
case 0xc3:
case 0xc4:
case 0xc5:
case 0xc6:
case 0xc7:
// MPEG audio
aux_packs++;
if (!new_mpeg_audio_id (id))
skipped_aux_packs++;
break;
case 0xbb:
// system header/private 2: PCI/DSI
nav_packs++;
break;
case 0xbe:
// padding
skipped_aux_packs++;
data_length = ptr [4] << 8;
data_length |= ptr [5];
if (14 + data_length != SECT_SIZE - 6)
fatal (TQString("Bad padding packet length at %1: %2").arg(rtell (ptr)).arg(data_length));
break;
default:
// fatal("Encountered stream ID %02x at %llu, "
// "probably bad MPEG2 program stream", id, rtell (ptr));
break;
}
}
eof = 1;
return seq_length;
}
// re-packetize the video ES
// `ptr' points to original PES packet where to put the video data
// `voptr' points to first unpacketized byte in vobuf
// `avail' specifies number of bytes remaining in vobuf
// returns number of ES bytes in generated PES packet
int k9vamps::gen_video_packet (uchar *ptr, uchar *voptr, int avail) {
int i, header_data_length, data_length, padding_length;
// if original PES holds optional data (e.g. DTS/PTS) we must keep it
header_data_length = (ptr [7] & 0xc0) == 0xc0 ? ptr [8] : 0;
data_length = SECT_SIZE - (14 + 6 + 3 + header_data_length);
if (avail >= data_length) {
// write out a full video packet (usually 2025 byte)
tc_memcpy (ptr + 6 + 3 + header_data_length, voptr, data_length);
ptr [4] = (SECT_SIZE - (14 + 6)) >> 8;
ptr [5] = (SECT_SIZE - (14 + 6)) & 0xff;
ptr [8] = header_data_length;
return data_length;
}
if (avail < data_length - 6) {
// write a short video packet and a padding packet
tc_memcpy (ptr + 6 + 3 + header_data_length, voptr, avail);
ptr [4] = (3 + header_data_length + avail) >> 8;
ptr [5] = 3 + header_data_length + avail;
ptr [8] = header_data_length;
// generate padding packet
ptr += 6 + 3 + header_data_length + avail;
padding_length = data_length - (avail + 6);
padding_bytes += padding_length + 6;
ptr [0] = 0;
ptr [1] = 0;
ptr [2] = 1;
ptr [3] = 0xbe;
ptr [4] = padding_length >> 8;
ptr [5] = padding_length;
for (i = 0; i < padding_length; i++)
ptr [6+i] = 0xff;
return avail;
}
// write a padded video packet (1 to 6 padding bytes)
padding_length = data_length - avail;
padding_bytes += padding_length;
memset (ptr + 6 + 3 + header_data_length, 0xff, padding_length);
header_data_length += padding_length;
tc_memcpy (ptr + 6 + 3 + header_data_length, voptr, avail);
ptr [4] = (SECT_SIZE - (14 + 6)) >> 8;
ptr [5] = (SECT_SIZE - (14 + 6)) & 0xff;
ptr [8] = header_data_length;
return avail;
}
// this is phase 2 of vaporization
// the shrunk video ES is re-packetized by using the source PES packets
// unused PS packs are skipped
// only wanted private stream 1 and MPEG audio packs are copied
// all nav packs are copied
void k9vamps::vap_phase2 (int seq_length) {
int i, id, avail, data_length;
uchar *ptr, *voptr = vobuf, *vohwp = vobuf + volen;
for (i = 0; i < seq_length; i += SECT_SIZE) {
ptr = rptr + 14;
id = ptr [3];
switch (id) {
case 0xe0:
// video
avail = vohwp - voptr;
if (avail) {
// still some video output data left
voptr += gen_video_packet (ptr, voptr, avail);
copy (SECT_SIZE);
} else {
// no video output data left - skip input sector
skip (SECT_SIZE);
skipped_video_packs++;
}
break;
case 0xbd:
// private 1: audio/subpicture
copy_private_1 (ptr);
break;
case 0xc0:
case 0xc1:
case 0xc2:
case 0xc3:
case 0xc4:
case 0xc5:
case 0xc6:
case 0xc7:
// MPEG audio
copy_mpeg_audio (ptr);
break;
case 0xbb:
// system header/private 2: PCI/DSI
copy (SECT_SIZE);
break;
case 0xbe:
// padding
data_length = ptr [4] << 8;
data_length |= ptr [5];
if (14 + data_length != SECT_SIZE - 6)
fatal (TQString("Bad padding packet length at %1: %2").arg(rtell (ptr)).arg(data_length));
//JMP: à vérifier
skip (SECT_SIZE);
break;
default:
copy (SECT_SIZE);
// fatal("Encountered stream ID %02x at %llu, "
// "probably bad MPEG2 program stream", id, rtell (ptr));
}
if (wptr == wbuf + WBUF_SIZE)
// end of write buffer reached --> flush it to disk
flush ();
}
}
TQString & k9vamps::geterrMsg() {
return m_errMsg;
}
bool k9vamps::geterror() {
return m_error;
}
// entry point from main()
// the requant thread already has been started
void k9vamps::vaporize (void) {
int seq_length;
float fact = vap_fact;
// process PS up to but not including first sequence header
vap_leader ();
// just in case - maybe should spit out a warning/error here
if (eof)
return;
total_packs++;
nav_packs++;
total_packs++;
video_packs++;
// main loop
while (1) {
// do phase 1 of vaporization
seq_length = vap_phase1 ();
if (eof) {
// EOF on source PS
// process packs after and including last sequence header
vap_trailer (seq_length);
// only exit point from main loop
return;
}
//fprintf (stderr, "seq_length=%d\n", seq_length);
if (calc_ps_vap && vap_fact > 1.0f) {
// forecast video ES vaporization factor
// the basic formulars look like:
// vap_fact = total_packs/(restpacks+vop)
// restpacks = total_packs-(video_packs+skipped_aux_packs)
// fact = (video_packs*net-(gops*net/2+10))/(vop*net-(gops*net/2+10))
// net = SECT_SIZE-(14+9)
// 14: pack header size
// 9: PES header size
// 10: PTS+DTS size in PES header of sequence header
// You are welcome to double check everything here!
float vop, net;
net = (float) (SECT_SIZE - (14+9));
vop = video_packs + skipped_aux_packs -
(float) total_packs * (1.0f-1.0f/vap_fact);
fact = ((float) video_packs * net -
((float) sequence_headers * net/2.0f + 10.0f)) /
(vop * net - ((float) sequence_headers * net/2.0f + 10.0f));
//JMP
m_totfact+=fact ;
m_nbfact++;
m_avgfact=m_totfact/m_nbfact;
// requant seems to get stuck on factors < 1
if (fact < 1.0f)
fact = 1.0f;
if (verbose >= 2)
fprintf (stderr, "Info: Target video ES vaporization factor: %.3f\n",
fact);
}
vin_bytes += vilen;
if (fact > 1.0f) {
// do requantization
volen = requant (vobuf, vibuf, vilen, fact);
} else {
// don't do requantization
tc_memcpy (vobuf, vibuf, vilen);
volen = vilen;
}
vout_bytes += volen;
// do phase 2 of vaporization
vap_phase2 (seq_length);
//fprintf (stderr,
// "tot=%d, vid=%d, ps1=%d, nav=%d, sv=%d, sp1=%d, fact=%.3f\n",
// total_packs, video_packs, aux_packs, nav_packs,
// skipped_video_packs, skipped_aux_packs, fact);
}
}
uint64_t k9vamps::getOutputBytes() {
return bytes_written;
}
void k9vamps::abort() {
//fatal("vamps stopped");
setNoData();
if (m_requant !=NULL)
m_requant->wait();
if (m_bgUpdate!=NULL)
m_bgUpdate->wait();
}
// this is a *very* sophisticated kind of error handling :-)
void
k9vamps::fatal (TQString msg) {
m_errMsg=msg;
m_error=true;
if (m_requant !=NULL)
m_requant->terminate();
if (m_bgUpdate !=NULL)
m_bgUpdate->terminate();
terminate();
}
/**************************** BACKGROUND UPDATE **********************/
k9bgUpdate::k9bgUpdate(k9DVDBackup * _backup) {
m_backup = _backup;
}
void k9bgUpdate::update(uchar *_buffer,uint32_t _size) {
mutex.lock();
m_buffer=(uchar*)malloc(_size);
tc_memcpy(m_buffer,_buffer,_size);
m_size=_size;
start();
mutex.unlock();
}
void k9bgUpdate::run() {
m_backup->getOutput(m_buffer,m_size);
free(m_buffer);
}