mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Speeded up cVideoRepacker
This commit is contained in:
parent
5cd7945ab5
commit
f0741c95c0
1
HISTORY
1
HISTORY
@ -4280,3 +4280,4 @@ Video Disk Recorder Revision History
|
||||
Huelswitt).
|
||||
- Fixed handling "pending" timers that blocked others that actually could record
|
||||
(reported by Thomas Koch).
|
||||
- Speeded up cVideoRepacker (thanks to Reinhard Nissl).
|
||||
|
347
remux.c
347
remux.c
@ -11,7 +11,7 @@
|
||||
* The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>,
|
||||
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
|
||||
*
|
||||
* $Id: remux.c 1.53 2006/01/08 11:40:16 kls Exp $
|
||||
* $Id: remux.c 1.54 2006/02/03 16:19:02 kls Exp $
|
||||
*/
|
||||
|
||||
#include "remux.h"
|
||||
@ -248,6 +248,14 @@ private:
|
||||
scanPicture
|
||||
};
|
||||
int state;
|
||||
void HandleStartCode(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel);
|
||||
inline bool ScanDataForStartCodeSlow(const uchar *const Data);
|
||||
inline bool ScanDataForStartCodeFast(const uchar *&Data, const uchar *Limit);
|
||||
inline bool ScanDataForStartCode(const uchar *&Data, int &Done, int &Todo);
|
||||
inline void AdjustCounters(const int Delta, int &Done, int &Todo);
|
||||
inline bool ScanForEndOfPictureSlow(const uchar *&Data);
|
||||
inline bool ScanForEndOfPictureFast(const uchar *&Data, const uchar *Limit);
|
||||
inline bool ScanForEndOfPicture(const uchar *&Data, const uchar *Limit);
|
||||
public:
|
||||
cVideoRepacker(void);
|
||||
virtual void Reset(void);
|
||||
@ -267,6 +275,162 @@ void cVideoRepacker::Reset(void)
|
||||
state = syncing;
|
||||
}
|
||||
|
||||
void cVideoRepacker::HandleStartCode(const uchar *const Data, cRingBufferLinear *const ResultBuffer, const uchar *&Payload, const uchar StreamID, const ePesHeader MpegLevel)
|
||||
{
|
||||
// synchronisation is detected some bytes after frame start.
|
||||
const int SkippedBytesLimit = 4;
|
||||
|
||||
// which kind of start code have we got?
|
||||
switch (*Data) {
|
||||
case 0xB9 ... 0xFF: // system start codes
|
||||
LOG("cVideoRepacker: found system start code: stream seems to be scrambled or not demultiplexed");
|
||||
break;
|
||||
case 0xB0 ... 0xB1: // reserved start codes
|
||||
case 0xB6:
|
||||
LOG("cVideoRepacker: found reserved start code: stream seems to be scrambled");
|
||||
break;
|
||||
case 0xB4: // sequence error code
|
||||
LOG("cVideoRepacker: found sequence error code: stream seems to be damaged");
|
||||
case 0xB2: // user data start code
|
||||
case 0xB5: // extension start code
|
||||
break;
|
||||
case 0xB7: // sequence end code
|
||||
case 0xB3: // sequence header code
|
||||
case 0xB8: // group start code
|
||||
case 0x00: // picture start code
|
||||
if (state == scanPicture) {
|
||||
// the above start codes indicate that the current picture is done. So
|
||||
// push out the packet to start a new packet for the next picuture. If
|
||||
// the byte count get's negative then the current buffer ends in a
|
||||
// partitial start code that must be stripped off, as it shall be put
|
||||
// in the next packet.
|
||||
PushOutPacket(ResultBuffer, Payload, Data - 3 - Payload);
|
||||
// go on with syncing to the next picture
|
||||
state = syncing;
|
||||
}
|
||||
if (state == syncing) {
|
||||
if (initiallySyncing) // omit report for the typical initial case
|
||||
initiallySyncing = false;
|
||||
else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes
|
||||
LOG("cVideoRepacker: skipped %d bytes to sync on next picture", skippedBytes - SkippedBytesLimit);
|
||||
skippedBytes = 0;
|
||||
// if there is a PES header available, then use it ...
|
||||
if (pesHeaderBackupLen > 0) {
|
||||
// ISO 13818-1 says:
|
||||
// In the case of video, if a PTS is present in a PES packet header
|
||||
// it shall refer to the access unit containing the first picture start
|
||||
// code that commences in this PES packet. A picture start code commences
|
||||
// in PES packet if the first byte of the picture start code is present
|
||||
// in the PES packet.
|
||||
memcpy(pesHeader, pesHeaderBackup, pesHeaderBackupLen);
|
||||
pesHeaderLen = pesHeaderBackupLen;
|
||||
pesHeaderBackupLen = 0;
|
||||
}
|
||||
else {
|
||||
// ... otherwise create a continuation PES header
|
||||
pesHeaderLen = 0;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x01;
|
||||
pesHeader[pesHeaderLen++] = StreamID; // video stream ID
|
||||
pesHeader[pesHeaderLen++] = 0x00; // length still unknown
|
||||
pesHeader[pesHeaderLen++] = 0x00; // length still unknown
|
||||
|
||||
if (MpegLevel == phMPEG2) {
|
||||
pesHeader[pesHeaderLen++] = 0x80;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
}
|
||||
else
|
||||
pesHeader[pesHeaderLen++] = 0x0F;
|
||||
}
|
||||
// append the first three bytes of the start code
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x01;
|
||||
// the next packet's payload will begin with the fourth byte of
|
||||
// the start code (= the actual code)
|
||||
Payload = Data;
|
||||
// as there is no length information available, assume the
|
||||
// maximum we can hold in one PES packet
|
||||
packetTodo = maxPacketSize - pesHeaderLen;
|
||||
// go on with finding the picture data
|
||||
state++;
|
||||
}
|
||||
break;
|
||||
case 0x01 ... 0xAF: // slice start codes
|
||||
if (state == findPicture) {
|
||||
// go on with scanning the picture data
|
||||
state++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool cVideoRepacker::ScanDataForStartCodeSlow(const uchar *const Data)
|
||||
{
|
||||
scanner <<= 8;
|
||||
bool FoundStartCode = (scanner == 0x00000100);
|
||||
scanner |= *Data;
|
||||
return FoundStartCode;
|
||||
}
|
||||
|
||||
bool cVideoRepacker::ScanDataForStartCodeFast(const uchar *&Data, const uchar *Limit)
|
||||
{
|
||||
Limit--;
|
||||
|
||||
while (Data < Limit && (Data = (const uchar *)memchr(Data, 0x01, Limit - Data))) {
|
||||
if (Data[-2] || Data[-1])
|
||||
Data += 3;
|
||||
else {
|
||||
scanner = 0x00000100 | *++Data;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Data = Limit;
|
||||
unsigned long *Scanner = (unsigned long *)(Data - 3);
|
||||
scanner = ntohl(*Scanner);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cVideoRepacker::ScanDataForStartCode(const uchar *&Data, int &Done, int &Todo)
|
||||
{
|
||||
const uchar *const DataOrig = Data;
|
||||
const int MinDataSize = 4;
|
||||
|
||||
if (Todo < MinDataSize || (state != syncing && packetTodo < MinDataSize))
|
||||
return ScanDataForStartCodeSlow(Data);
|
||||
|
||||
int Limit = Todo;
|
||||
if (state != syncing && Limit > packetTodo)
|
||||
Limit = packetTodo;
|
||||
|
||||
if (ScanDataForStartCodeSlow(Data))
|
||||
return true;
|
||||
|
||||
if (ScanDataForStartCodeSlow(++Data)) {
|
||||
AdjustCounters(1, Done, Todo);
|
||||
return true;
|
||||
}
|
||||
++Data;
|
||||
|
||||
bool FoundStartCode = ScanDataForStartCodeFast(Data, DataOrig + Limit);
|
||||
AdjustCounters(Data - DataOrig, Done, Todo);
|
||||
return FoundStartCode;
|
||||
}
|
||||
|
||||
void cVideoRepacker::AdjustCounters(const int Delta, int &Done, int &Todo)
|
||||
{
|
||||
Done += Delta;
|
||||
Todo -= Delta;
|
||||
|
||||
if (state <= syncing)
|
||||
skippedBytes += Delta;
|
||||
else
|
||||
packetTodo -= Delta;
|
||||
}
|
||||
|
||||
void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count)
|
||||
{
|
||||
// synchronisation is detected some bytes after frame start.
|
||||
@ -300,98 +464,9 @@ void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
|
||||
if (state <= syncing)
|
||||
skippedBytes++;
|
||||
// did we reach a start code?
|
||||
scanner <<= 8;
|
||||
if (scanner != 0x00000100)
|
||||
scanner |= *data;
|
||||
else {
|
||||
scanner |= *data;
|
||||
|
||||
// which kind of start code have we got?
|
||||
switch (*data) {
|
||||
case 0xB9 ... 0xFF: // system start codes
|
||||
LOG("cVideoRepacker: found system start code: stream seems to be scrambled or not demultiplexed");
|
||||
break;
|
||||
case 0xB0 ... 0xB1: // reserved start codes
|
||||
case 0xB6:
|
||||
LOG("cVideoRepacker: found reserved start code: stream seems to be scrambled");
|
||||
break;
|
||||
case 0xB4: // sequence error code
|
||||
LOG("cVideoRepacker: found sequence error code: stream seems to be damaged");
|
||||
case 0xB2: // user data start code
|
||||
case 0xB5: // extension start code
|
||||
break;
|
||||
case 0xB7: // sequence end code
|
||||
case 0xB3: // sequence header code
|
||||
case 0xB8: // group start code
|
||||
case 0x00: // picture start code
|
||||
if (state == scanPicture) {
|
||||
// the above start codes indicate that the current picture is done. So
|
||||
// push out the packet to start a new packet for the next picuture. If
|
||||
// the byte count get's negative then the current buffer ends in a
|
||||
// partitial start code that must be stripped off, as it shall be put
|
||||
// in the next packet.
|
||||
PushOutPacket(ResultBuffer, payload, data - 3 - payload);
|
||||
// go on with syncing to the next picture
|
||||
state = syncing;
|
||||
}
|
||||
if (state == syncing) {
|
||||
if (initiallySyncing) // omit report for the typical initial case
|
||||
initiallySyncing = false;
|
||||
else if (skippedBytes > SkippedBytesLimit) // report that syncing dropped some bytes
|
||||
LOG("cVideoRepacker: skipped %d bytes to sync on next picture", skippedBytes - SkippedBytesLimit);
|
||||
skippedBytes = 0;
|
||||
// if there is a PES header available, then use it ...
|
||||
if (pesHeaderBackupLen > 0) {
|
||||
// ISO 13818-1 says:
|
||||
// In the case of video, if a PTS is present in a PES packet header
|
||||
// it shall refer to the access unit containing the first picture start
|
||||
// code that commences in this PES packet. A picture start code commences
|
||||
// in PES packet if the first byte of the picture start code is present
|
||||
// in the PES packet.
|
||||
memcpy(pesHeader, pesHeaderBackup, pesHeaderBackupLen);
|
||||
pesHeaderLen = pesHeaderBackupLen;
|
||||
pesHeaderBackupLen = 0;
|
||||
}
|
||||
else {
|
||||
// ... otherwise create a continuation PES header
|
||||
pesHeaderLen = 0;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x01;
|
||||
pesHeader[pesHeaderLen++] = Data[3]; // video stream ID
|
||||
pesHeader[pesHeaderLen++] = 0x00; // length still unknown
|
||||
pesHeader[pesHeaderLen++] = 0x00; // length still unknown
|
||||
|
||||
if (mpegLevel == phMPEG2) {
|
||||
pesHeader[pesHeaderLen++] = 0x80;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
}
|
||||
else
|
||||
pesHeader[pesHeaderLen++] = 0x0F;
|
||||
}
|
||||
// append the first three bytes of the start code
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x00;
|
||||
pesHeader[pesHeaderLen++] = 0x01;
|
||||
// the next packet's payload will begin with the fourth byte of
|
||||
// the start code (= the actual code)
|
||||
payload = data;
|
||||
// as there is no length information available, assume the
|
||||
// maximum we can hold in one PES packet
|
||||
packetTodo = maxPacketSize - pesHeaderLen;
|
||||
// go on with finding the picture data
|
||||
state++;
|
||||
}
|
||||
break;
|
||||
case 0x01 ... 0xAF: // slice start codes
|
||||
if (state == findPicture) {
|
||||
// go on with scanning the picture data
|
||||
state++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ScanDataForStartCode(data, done, todo))
|
||||
HandleStartCode(data, ResultBuffer, payload, Data[3], mpegLevel);
|
||||
// move on
|
||||
data++;
|
||||
done++;
|
||||
todo--;
|
||||
@ -501,6 +576,79 @@ void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data,
|
||||
}
|
||||
}
|
||||
|
||||
bool cVideoRepacker::ScanForEndOfPictureSlow(const uchar *&Data)
|
||||
{
|
||||
localScanner <<= 8;
|
||||
localScanner |= *Data++;
|
||||
// check start codes which follow picture data
|
||||
switch (localScanner) {
|
||||
case 0x00000100: // picture start code
|
||||
case 0x000001B8: // group start code
|
||||
case 0x000001B3: // sequence header code
|
||||
case 0x000001B7: // sequence end code
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cVideoRepacker::ScanForEndOfPictureFast(const uchar *&Data, const uchar *Limit)
|
||||
{
|
||||
Limit--;
|
||||
|
||||
while (Data < Limit && (Data = (const uchar *)memchr(Data, 0x01, Limit - Data))) {
|
||||
if (Data[-2] || Data[-1])
|
||||
Data += 3;
|
||||
else {
|
||||
localScanner = 0x00000100 | *++Data;
|
||||
// check start codes which follow picture data
|
||||
switch (localScanner) {
|
||||
case 0x00000100: // picture start code
|
||||
case 0x000001B8: // group start code
|
||||
case 0x000001B3: // sequence header code
|
||||
case 0x000001B7: // sequence end code
|
||||
Data++;
|
||||
return true;
|
||||
default:
|
||||
Data += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Data = Limit + 1;
|
||||
unsigned long *LocalScanner = (unsigned long *)(Data - 4);
|
||||
localScanner = ntohl(*LocalScanner);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cVideoRepacker::ScanForEndOfPicture(const uchar *&Data, const uchar *Limit)
|
||||
{
|
||||
const uchar *const DataOrig = Data;
|
||||
const int MinDataSize = 4;
|
||||
bool FoundEndOfPicture;
|
||||
|
||||
if (Limit - Data <= MinDataSize) {
|
||||
FoundEndOfPicture = false;
|
||||
while (Data < Limit) {
|
||||
if (ScanForEndOfPictureSlow(Data)) {
|
||||
FoundEndOfPicture = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
FoundEndOfPicture = true;
|
||||
if (!ScanForEndOfPictureSlow(Data)) {
|
||||
if (!ScanForEndOfPictureSlow(Data)) {
|
||||
if (!ScanForEndOfPictureFast(Data, Limit))
|
||||
FoundEndOfPicture = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localStart += (Data - DataOrig);
|
||||
return FoundEndOfPicture;
|
||||
}
|
||||
|
||||
int cVideoRepacker::BreakAt(const uchar *Data, int Count)
|
||||
{
|
||||
if (initiallySyncing)
|
||||
@ -522,20 +670,9 @@ int cVideoRepacker::BreakAt(const uchar *Data, int Count)
|
||||
const uchar *data = Data + PesPayloadOffset + localStart;
|
||||
const uchar *limit = Data + Count;
|
||||
// scan data
|
||||
while (data < limit) {
|
||||
localStart++;
|
||||
localScanner <<= 8;
|
||||
localScanner |= *data++;
|
||||
// check start codes which follow picture data
|
||||
switch (localScanner) {
|
||||
case 0x00000100: // picture start code
|
||||
case 0x000001B8: // group start code
|
||||
case 0x000001B3: // sequence header code
|
||||
case 0x000001B7: // sequence end code
|
||||
if (ScanForEndOfPicture(data, limit))
|
||||
return data - Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
// just fill up packet and append next start code
|
||||
return PesPayloadOffset + packetTodo + 4;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user