diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-17 00:32:19 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-17 00:32:19 +0000 |
commit | 0d382a262c0638d0f572fc37193ccc5ed3dc895f (patch) | |
tree | 8578dcddfce4191f3f7a142a37769df7add48475 /k9vamps/k9vamps.cpp | |
download | k9copy-0d382a262c0638d0f572fc37193ccc5ed3dc895f.tar.gz k9copy-0d382a262c0638d0f572fc37193ccc5ed3dc895f.zip |
Added old abandoned version of k9copy
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/k9copy@1091546 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'k9vamps/k9vamps.cpp')
-rwxr-xr-x | k9vamps/k9vamps.cpp | 1100 |
1 files changed, 1100 insertions, 0 deletions
diff --git a/k9vamps/k9vamps.cpp b/k9vamps/k9vamps.cpp new file mode 100755 index 0000000..b077fb8 --- /dev/null +++ b/k9vamps/k9vamps.cpp @@ -0,0 +1,1100 @@ +// +// C++ Interface: k9vamps +// +// Description: A transcription from Vamps in C++ +// +// +// Author: Jean-Michel PETIT <[email protected]>, (C) 2006 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "k9vamps.h" +#include <qapplication.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(QFile *_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 (QString("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(QString ("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 (QString("Not an MPEG2 video packet at %1").arg(rtell (ptr))); + + if (ptr [7]) { + if ((ptr [7] & 0xc0) != 0xc0) + qDebug (QString("First video packet in sequence starting at %1 misses PTS or DTS, flags=%2").arg(rtell (ptr)).arg(ptr [7])); + 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) + qDebug (QString("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) + qDebug (QString("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) +// qDebug("requant error"); + + double realrqtfact=(double)(vin_bytes) / (double)(vout_bytes+rv); + avgdiff = ((m_avgfact) /realrqtfact); + + //qDebug ("factor : " +QString::number(m_avgfact) +" --> " +QString::number((float)n/(float)rv) +" avgdiff : " + QString::number(avgdiff) +" rqt_visize :" +QString::number(m_requant->rqt_visize) +" ps_size :" +QString::number(ps_size) + " vin_bytes :" + QString::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 (QString("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 (QString("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 (QString("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 (QString("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 (); + } +} + +QString & 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 (QString 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); +} |