mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-23 19:31:44 +00:00
Cleanups & speed improvements for the MPEG video parser. Patch by Steve Lhomme (see AUTHORS).
This commit is contained in:
parent
64f306d8eb
commit
ac9c14b265
@ -128,20 +128,19 @@ int32_t M2VParser::InitParser(){
|
||||
//Gotta find a sequence header now
|
||||
MPEGChunk* chunk;
|
||||
//MPEGChunk* seqHdrChunk;
|
||||
for(int i = 0; i < chunks.size(); i++){
|
||||
for(size_t i = 0; i < chunks.size(); i++){
|
||||
chunk = chunks[i];
|
||||
if(chunk->GetType() == MPEG_VIDEO_SEQUENCE_START_CODE){
|
||||
//Copy the header for later, we must copy because the actual chunk will be deleted in a bit
|
||||
binary * hdrData = new binary[chunk->GetSize()];
|
||||
memcpy(hdrData, chunk->GetPointer(), chunk->GetSize());
|
||||
seqHdrChunk = new MPEGChunk(hdrData, chunk->GetSize()); //Save this for adding as private data...
|
||||
MPEG2SequenceHeader seqHdr = ParseSequenceHeader(chunk);
|
||||
m_seqHdr = seqHdr;
|
||||
ParseSequenceHeader(chunk, m_seqHdr);
|
||||
|
||||
//Look for sequence extension to identify mpeg2
|
||||
binary* pData = chunk->GetPointer();
|
||||
for(int i = 3; i < chunk->GetSize() - 4; i++){
|
||||
if(pData[i] == 0x00 && pData[i+1] == 0x00 && pData[i+2] == 0x01 && pData[i+3] == 0xb5 && ((pData[i+4] & 0xF0) == 0x10)){
|
||||
for(size_t j = 3; i < chunk->GetSize() - 4; i++){
|
||||
if(pData[j] == 0x00 && pData[j+1] == 0x00 && pData[j+2] == 0x01 && pData[j+3] == 0xb5 && ((pData[j+4] & 0xF0) == 0x10)){
|
||||
mpegVersion = 2;
|
||||
break;
|
||||
}
|
||||
@ -181,7 +180,7 @@ MediaTime M2VParser::GetFrameDuration(MPEG2PictureHeader picHdr){
|
||||
}
|
||||
}
|
||||
|
||||
int32_t M2VParser::GetState(){
|
||||
MPEG2ParserState_e M2VParser::GetState(){
|
||||
FillQueues();
|
||||
if(!buffers.empty())
|
||||
parserState = MPV_PARSER_STATE_FRAME;
|
||||
@ -193,15 +192,16 @@ int32_t M2VParser::GetState(){
|
||||
return parserState;
|
||||
}
|
||||
|
||||
int32_t M2VParser::CountBFrames(){
|
||||
MediaTime M2VParser::CountBFrames(){
|
||||
//We count after the first chunk.
|
||||
int32_t count = 0;
|
||||
MediaTime count = 0;
|
||||
if(m_eos) return 0;
|
||||
if(notReachedFirstGOP) return 0;
|
||||
for(int i = 1; i < chunks.size(); i++){
|
||||
for(size_t i = 1; i < chunks.size(); i++){
|
||||
MPEGChunk* c = chunks[i];
|
||||
if(c->GetType() == MPEG_VIDEO_PICTURE_START_CODE){
|
||||
MPEG2PictureHeader h = ParsePictureHeader(c);
|
||||
MPEG2PictureHeader h;
|
||||
ParsePictureHeader(c, h);
|
||||
if(h.frameType == MPEG2_B_FRAME){
|
||||
count += GetFrameDuration(h);
|
||||
}else{
|
||||
@ -249,9 +249,9 @@ int32_t M2VParser::QueueFrame(MPEGChunk* seqHdr, MPEGChunk* chunk, MediaTime tim
|
||||
outBuf->firstRef = (MediaTime)(firstRef * (1000000000/(m_seqHdr.frameRate*2)));
|
||||
outBuf->secondRef = (MediaTime)(secondRef * (1000000000/(m_seqHdr.frameRate*2)));
|
||||
}
|
||||
outBuf->rff = (bool) picHdr.repeatFirstField;
|
||||
outBuf->tff = (bool) picHdr.topFieldFirst;
|
||||
outBuf->progressive = (bool) picHdr.progressive;
|
||||
outBuf->rff = (picHdr.repeatFirstField != 0);
|
||||
outBuf->tff = (picHdr.topFieldFirst != 0);
|
||||
outBuf->progressive = (picHdr.progressive != 0);
|
||||
outBuf->pictureStructure = (uint8_t) picHdr.pictureStructure;
|
||||
buffers.push(outBuf);
|
||||
return 0;
|
||||
@ -285,7 +285,7 @@ int32_t M2VParser::FillQueues(){
|
||||
if(chunk->GetType() == MPEG_VIDEO_SEQUENCE_START_CODE){
|
||||
if (chunks.size() == 1) return -1;
|
||||
if(seqHdr) delete seqHdr;
|
||||
m_seqHdr = ParseSequenceHeader(chunk);
|
||||
ParseSequenceHeader(chunk, m_seqHdr);
|
||||
seqHdr = chunk;
|
||||
}else{
|
||||
delete chunk; //Skip all non picture, non seq headers
|
||||
@ -298,8 +298,9 @@ int32_t M2VParser::FillQueues(){
|
||||
}
|
||||
chunk = chunks.front();
|
||||
}
|
||||
MPEG2PictureHeader picHdr = ParsePictureHeader(chunk);
|
||||
int bcount;
|
||||
MPEG2PictureHeader picHdr;
|
||||
ParsePictureHeader(chunk, picHdr);
|
||||
MediaTime bcount;
|
||||
if(myTime == nextSkip){
|
||||
myTime+=nextSkipDuration;
|
||||
currentStampingTime=myTime;
|
||||
@ -318,7 +319,7 @@ int32_t M2VParser::FillQueues(){
|
||||
}
|
||||
ShoveRef(myTime);
|
||||
QueueFrame(seqHdr,chunk,myTime,picHdr);
|
||||
if(notReachedFirstGOP) notReachedFirstGOP = false;
|
||||
notReachedFirstGOP = false;
|
||||
break;
|
||||
case MPEG2_P_FRAME:
|
||||
bcount = CountBFrames();
|
||||
|
@ -27,10 +27,12 @@
|
||||
#include <stdio.h>
|
||||
#include <queue>
|
||||
|
||||
#define MPV_PARSER_STATE_FRAME 0
|
||||
#define MPV_PARSER_STATE_NEED_DATA 1
|
||||
#define MPV_PARSER_STATE_EOS -1
|
||||
#define MPV_PARSER_STATE_ERROR -2
|
||||
enum MPEG2ParserState_e {
|
||||
MPV_PARSER_STATE_FRAME,
|
||||
MPV_PARSER_STATE_NEED_DATA,
|
||||
MPV_PARSER_STATE_EOS,
|
||||
MPV_PARSER_STATE_ERROR
|
||||
};
|
||||
|
||||
class MPEGFrame {
|
||||
public:
|
||||
@ -68,13 +70,13 @@ private:
|
||||
MediaTime nextSkipDuration;
|
||||
MediaTime secondRef;
|
||||
uint8_t mpegVersion;
|
||||
int32_t parserState;
|
||||
MPEG2ParserState_e parserState;
|
||||
MPEGVideoBuffer * mpgBuf;
|
||||
|
||||
int32_t InitParser();
|
||||
void DumpQueues();
|
||||
int32_t FillQueues();
|
||||
int32_t CountBFrames();
|
||||
MediaTime CountBFrames();
|
||||
void ShoveRef(MediaTime ref);
|
||||
MediaTime GetFrameDuration(MPEG2PictureHeader picHdr);
|
||||
int32_t QueueFrame(MPEGChunk* seqHdr, MPEGChunk* chunk, MediaTime timecode, MPEG2PictureHeader picHdr);
|
||||
@ -94,7 +96,7 @@ public:
|
||||
return seqHdrChunk;
|
||||
}
|
||||
|
||||
uint8_t GetMPEGVersion(){
|
||||
uint8_t GetMPEGVersion() const{
|
||||
return mpegVersion;
|
||||
}
|
||||
|
||||
@ -110,7 +112,7 @@ public:
|
||||
int32_t WriteData(binary* data, uint32_t dataSize);
|
||||
|
||||
//Returns the current state of the parser
|
||||
int32_t GetState();
|
||||
MPEG2ParserState_e GetState();
|
||||
|
||||
//Sets "end of stream" status on the buffer, forces timestamping of frames waiting.
|
||||
//Do not call this without good reason.
|
||||
|
@ -70,23 +70,14 @@ void MPEGVideoBuffer::UpdateState(){
|
||||
if(test != -1) //We found a new startcode
|
||||
chunkEnd = test;
|
||||
}
|
||||
if(chunkStart == -1){
|
||||
if(chunkStart == -1 || chunkEnd == -1){
|
||||
state = MPEG2_BUFFER_STATE_NEED_MORE_DATA;
|
||||
return;
|
||||
}else if(chunkEnd == -1){
|
||||
state = MPEG2_BUFFER_STATE_NEED_MORE_DATA;
|
||||
return;
|
||||
}else{
|
||||
assert(chunkStart >= 0 && chunkStart < chunkEnd && chunkEnd > 0);
|
||||
state = MPEG2_BUFFER_STATE_CHUNK_READY;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t MPEGVideoBuffer::GetState(){
|
||||
return state;
|
||||
}
|
||||
|
||||
MPEGChunk * MPEGVideoBuffer::ReadChunk(){
|
||||
MPEGChunk* myChunk = NULL;
|
||||
if(state == MPEG2_BUFFER_STATE_CHUNK_READY){
|
||||
@ -121,14 +112,9 @@ int32_t MPEGVideoBuffer::Feed(binary* data, uint32_t numBytes){
|
||||
return res;
|
||||
}
|
||||
|
||||
MPEG2SequenceHeader ParseSequenceHeader(MPEGChunk* chunk){
|
||||
MPEG2SequenceHeader hdr;
|
||||
void ParseSequenceHeader(MPEGChunk* chunk, MPEG2SequenceHeader & hdr){
|
||||
binary* pos = chunk->GetPointer();
|
||||
uint8_t haveSeqExt = 0;
|
||||
if(chunk->GetType() != MPEG_VIDEO_SEQUENCE_START_CODE){
|
||||
//printf("Don't feed parse_sequence_header a chunk that isn't a sequence header!!!\n");
|
||||
return hdr;
|
||||
}
|
||||
//Parse out the resolution info, horizontal first
|
||||
pos+=4; //Skip the start code
|
||||
hdr.width = (((unsigned int)pos[0]) << 4) | (((unsigned int) pos[1])>>4); //xx x0 00
|
||||
@ -206,18 +192,15 @@ MPEG2SequenceHeader ParseSequenceHeader(MPEGChunk* chunk){
|
||||
}else{
|
||||
hdr.progressiveSequence = 0;
|
||||
}
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
MPEG2GOPHeader ParseGOPHeader(MPEGChunk* chunk){
|
||||
MPEG2GOPHeader hdr;
|
||||
binary* pos = chunk->GetPointer();
|
||||
uint32_t timecode;
|
||||
bool ParseGOPHeader(MPEGChunk* chunk, MPEG2GOPHeader & hdr){
|
||||
if(chunk->GetType() != MPEG_VIDEO_GOP_START_CODE){
|
||||
//printf("Don't feed parse_gop_header a chunk that isn't a gop header!!!\n");
|
||||
return hdr;
|
||||
return false;
|
||||
}
|
||||
binary* pos = chunk->GetPointer();
|
||||
uint32_t timecode;
|
||||
pos+=4; //skip the startcode
|
||||
//Parse GOP timecode structure
|
||||
timecode = ((uint32_t)pos[0] << 24) |
|
||||
@ -234,19 +217,17 @@ MPEG2GOPHeader ParseGOPHeader(MPEGChunk* chunk){
|
||||
}else{
|
||||
hdr.closedGOP = 0;
|
||||
}
|
||||
return hdr;
|
||||
return true;
|
||||
}
|
||||
|
||||
MPEG2PictureHeader ParsePictureHeader(MPEGChunk* chunk){
|
||||
MPEG2PictureHeader hdr;
|
||||
binary* pos = chunk->GetPointer();
|
||||
// int i = 0;
|
||||
int havePicExt = 0;
|
||||
uint32_t temp = 0;
|
||||
bool ParsePictureHeader(MPEGChunk* chunk, MPEG2PictureHeader & hdr){
|
||||
if(chunk->GetType() != MPEG_VIDEO_PICTURE_START_CODE){
|
||||
//printf("Don't feed parse_picture_header a chunk that isn't a picture!!!\n");
|
||||
return hdr;
|
||||
return false;
|
||||
}
|
||||
binary* pos = chunk->GetPointer();
|
||||
int havePicExt = 0;
|
||||
uint32_t temp = 0;
|
||||
pos+=4;
|
||||
temp = (((uint32_t)pos[0]) << 8) | (pos[1] & 0xC0);
|
||||
hdr.temporalReference = temp >> 6;
|
||||
@ -284,5 +265,5 @@ MPEG2PictureHeader ParsePictureHeader(MPEGChunk* chunk){
|
||||
hdr.progressive = (pos[0] & 0x80);
|
||||
}
|
||||
|
||||
return hdr;
|
||||
return true;
|
||||
}
|
||||
|
@ -33,10 +33,12 @@
|
||||
#define MPEG_VIDEO_GOP_START_CODE 0xb8
|
||||
#define MPEG_VIDEO_USER_START_CODE 0xb2
|
||||
|
||||
#define MPEG2_BUFFER_STATE_NEED_MORE_DATA 1
|
||||
#define MPEG2_BUFFER_STATE_CHUNK_READY 2
|
||||
#define MPEG2_BUFFER_STATE_EMPTY 0
|
||||
#define MPEG2_BUFFER_INVALID -1
|
||||
enum MPEG2BufferState_e {
|
||||
MPEG2_BUFFER_STATE_NEED_MORE_DATA,
|
||||
MPEG2_BUFFER_STATE_CHUNK_READY,
|
||||
MPEG2_BUFFER_STATE_EMPTY,
|
||||
MPEG2_BUFFER_INVALID
|
||||
};
|
||||
|
||||
#define MPEG2_I_FRAME 1
|
||||
#define MPEG2_P_FRAME 2
|
||||
@ -90,11 +92,11 @@ public:
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
uint8_t GetType(){
|
||||
inline uint8_t GetType() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
uint32_t GetSize(){
|
||||
inline uint32_t GetSize() const{
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -106,19 +108,19 @@ public:
|
||||
return data[i];
|
||||
}
|
||||
|
||||
binary * GetPointer(){
|
||||
inline binary * GetPointer(){
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
MPEG2SequenceHeader ParseSequenceHeader(MPEGChunk* chunk);
|
||||
MPEG2PictureHeader ParsePictureHeader(MPEGChunk* chunk);
|
||||
MPEG2GOPHeader ParseGOPHeader(MPEGChunk* chunk);
|
||||
void ParseSequenceHeader(MPEGChunk* chunk, MPEG2SequenceHeader & hdr);
|
||||
bool ParsePictureHeader(MPEGChunk* chunk, MPEG2PictureHeader & hdr);
|
||||
bool ParseGOPHeader(MPEGChunk* chunk, MPEG2GOPHeader & hdr);
|
||||
|
||||
class MPEGVideoBuffer{
|
||||
private:
|
||||
CircBuffer * myBuffer;
|
||||
uint32_t state;
|
||||
MPEG2BufferState_e state;
|
||||
int32_t chunkStart;
|
||||
int32_t chunkEnd;
|
||||
void UpdateState();
|
||||
@ -135,7 +137,7 @@ public:
|
||||
delete myBuffer;
|
||||
}
|
||||
|
||||
uint32_t GetState();
|
||||
inline MPEG2BufferState_e GetState() const { return state; }
|
||||
|
||||
int32_t GetFreeBufferSpace(){
|
||||
return (myBuffer->buf_capacity - myBuffer->bytes_in_buf);
|
||||
|
Loading…
Reference in New Issue
Block a user