Author: robux4
Date: 2005-04-10 16:55:15 +0400 (Sun, 10 Apr 2005)
New Revision: 1122
Added:
trunk/DvdMenuXtractor/mpegparser/
trunk/DvdMenuXtractor/mpegparser/CircBuffer.cpp
trunk/DvdMenuXtractor/mpegparser/CircBuffer.h
trunk/DvdMenuXtractor/mpegparser/M2VParser.cpp
trunk/DvdMenuXtractor/mpegparser/M2VParser.h
trunk/DvdMenuXtractor/mpegparser/MPEGVideoBuffer.cpp
trunk/DvdMenuXtractor/mpegparser/MPEGVideoBuffer.h
trunk/DvdMenuXtractor/mpegparser/Types.h
Modified:
trunk/DvdMenuXtractor/DvdMenuXtractor.vcproj
trunk/DvdMenuXtractor/VobParser.cpp
trunk/DvdMenuXtractor/VobParser.h
Log:
DMX: let's use Spyder's MPEG parser class
Modified: trunk/DvdMenuXtractor/DvdMenuXtractor.vcproj
===================================================================
--- trunk/DvdMenuXtractor/DvdMenuXtractor.vcproj 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/DvdMenuXtractor.vcproj 2005-04-10 12:55:15 UTC (rev 1122)
@@ -22,10 +22,10 @@
Name="VCCLCompilerTool"
Optimization="1"
InlineFunctionExpansion="1"
- AdditionalIncludeDirectories=""$(ProjectDir)\win32";"$(ProjectDir)\libdvdread";"D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\include";"D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\lib\vc_lib\mswud""
+ AdditionalIncludeDirectories=""$(ProjectDir)\win32";"$(ProjectDir)\libdvdread";"D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\include";"D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\lib\vc_lib\msw""
PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;__WINDOWS__;__WXMSW__;__WIN95__;__WIN32__;WINVER=0x0400;STRICT"
StringPooling="TRUE"
- RuntimeLibrary="4"
+ RuntimeLibrary="2"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Release/DvdMenuXtractor.pch"
@@ -40,11 +40,11 @@
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib wsock32.lib wxmsw.lib"
+ AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib wsock32.lib"
OutputFile=".\Release/DvdMenuXtractor.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
- IgnoreDefaultLibraryNames="libc.lib,libci.lib,msvcrtd.lib"
+ IgnoreDefaultLibraryNames=""
ProgramDatabaseFile=".\Release/DvdMenuXtractor.pdb"
SubSystem="2"
TargetMachine="1"/>
@@ -65,7 +65,8 @@
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
- Culture="1036"/>
+ Culture="0"
+ AdditionalIncludeDirectories=""D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\include""/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
@@ -87,7 +88,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories=""$(ProjectDir)\win32";"$(ProjectDir)\libdvdread";"D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\include";"D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\lib\vc_lib\mswud""
+ AdditionalIncludeDirectories=""$(ProjectDir)\win32";"$(ProjectDir)\libdvdread";"D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\include";"D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\lib\vc_lib\mswd""
PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
@@ -133,7 +134,7 @@
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
- Culture="1036"
+ Culture="0"
AdditionalIncludeDirectories=""D:\Perso\Programmes\wxMSW-2.5.4\wxWidgets-2.5.4\include""/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
@@ -421,6 +422,52 @@
RelativePath=".\iso\iso_lang.h">
</File>
</Filter>
+ <Filter
+ Name="mpegparser"
+ Filter="">
+ <File
+ RelativePath=".\mpegparser\CircBuffer.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\mpegparser\CircBuffer.h">
+ </File>
+ <File
+ RelativePath=".\mpegparser\M2VParser.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\mpegparser\M2VParser.h">
+ </File>
+ <File
+ RelativePath=".\mpegparser\MPEGVideoBuffer.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\mpegparser\MPEGVideoBuffer.h">
+ </File>
+ <File
+ RelativePath=".\mpegparser\Types.h">
+ </File>
+ </Filter>
<File
RelativePath=".\README.txt">
</File>
Modified: trunk/DvdMenuXtractor/VobParser.cpp
===================================================================
--- trunk/DvdMenuXtractor/VobParser.cpp 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/VobParser.cpp 2005-04-10 12:55:15 UTC (rev 1122)
@@ -927,6 +927,38 @@
// ============================================================================
+void VideoDemuxWriter::ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, uint32_t end_time, const wxString & debug)
+{
+ int bytes_probed = 0;
+
+ while (true) {
+ MPEG2ParserState state;
+
+ state = m_parser.GetState();
+
+ if (state == MPV_PARSER_STATE_NEED_DATA) {
+ int bytes_to_read;
+
+ if (bytes_probed >= size)
+ break;
+
+ bytes_to_read = (m_parser.GetFreeBufferSpace() < size) ? m_parser.GetFreeBufferSpace() : size;
+ bytes_probed += bytes_to_read;
+
+ m_parser.WriteData(buff, bytes_to_read);
+
+ } else if (state == MPV_PARSER_STATE_FRAME) {
+ MPEGFrame* current_frame = m_parser.ReadFrame();
+ }
+
+ else if ((state == MPV_PARSER_STATE_EOS) ||
+ (state == MPV_PARSER_STATE_ERROR))
+ break;
+ }
+
+ Write(buff, size, start_time, end_time, debug);
+}
+
void VideoDemuxWriter::SetBoundary(uint32_t start_timecode, uint32_t duration, const CellListElem *cell)
{
m_TimecodeFile = GetTimecodeFile();
Modified: trunk/DvdMenuXtractor/VobParser.h
===================================================================
--- trunk/DvdMenuXtractor/VobParser.h 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/VobParser.h 2005-04-10 12:55:15 UTC (rev 1122)
@@ -11,6 +11,7 @@
#include <stdarg.h>
#include <inttypes.h>
#include "dvdread/ifo_read.h"
+#include "mpegparser/M2VParser.h"
#include "wx/wx.h"
@@ -281,7 +282,7 @@
,m_last_end_timecode(0)
,m_is_still(false)
{}
- void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, uint32_t end_time, const wxString & debug) { Write(buff, size, start_time, end_time, debug); }
+ void ProcessStream(uint8_t* buff, uint32_t size, uint32_t start_time, uint32_t end_time, const wxString & debug);
void SetBoundary(uint32_t start_timecode, uint32_t duration, const CellListElem *cell);
~VideoDemuxWriter();
protected:
@@ -291,6 +292,8 @@
uint32_t m_last_start_timecode;
uint32_t m_last_end_timecode;
bool m_is_still;
+
+ M2VParser m_parser;
};
// ----------------------------------------------------------------------------
Added: trunk/DvdMenuXtractor/mpegparser/CircBuffer.cpp
===================================================================
--- trunk/DvdMenuXtractor/mpegparser/CircBuffer.cpp 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/mpegparser/CircBuffer.cpp 2005-04-10 12:55:15 UTC (rev 1122)
@@ -0,0 +1,110 @@
+/*****************************************************************************
+
+ Circular/Ring Buffer
+
+ Copyright(C) 2004 John Cannon <[email protected]>
+
+ This program is free software ; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation ; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program ; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ **/
+
+#include "CircBuffer.h"
+#include <string.h>
+#include <assert.h>
+
+CircBuffer::CircBuffer(uint32_t size){
+ m_buf = new binary[size];
+ read_ptr = m_buf;
+ write_ptr = m_buf;
+ buf_capacity = size;
+ bytes_in_buf = 0;
+}
+
+CircBuffer::~CircBuffer(){
+ if(m_buf)
+ delete [] m_buf;
+}
+
+int32_t CircBuffer::Skip(uint32_t numBytes){
+ assert(numBytes > 0);
+ if(can_read(numBytes)){
+ int32_t bbw = bytes_before_wrap_read(); //how many bytes we have before the buffer must be wrapped
+ if(bbw >= numBytes){
+ move_pointer(&read_ptr, numBytes);
+ bytes_in_buf -= numBytes;
+ }else{
+ if(bbw != 0){
+ numBytes -= bbw;
+ bytes_in_buf -= bbw;
+ move_pointer(&read_ptr, bbw); //Reset to beginning
+ }
+ bytes_in_buf -= numBytes;
+ move_pointer(&read_ptr, numBytes);
+ }
+ return 0;
+ }else{
+ return -1;
+ }
+}
+
+int32_t CircBuffer::Read(binary* dest, uint32_t numBytes){
+ if(can_read(numBytes)){
+ int32_t bbw = bytes_before_wrap_read(); //how many bytes we have before the buffer must be wrapped
+ if(bbw >= numBytes){
+ memcpy(dest, read_ptr, numBytes);
+ move_pointer(&read_ptr, numBytes);
+ bytes_in_buf -= numBytes;
+ }else{
+ if(bbw != 0){
+ memcpy(dest,read_ptr,bbw);
+ numBytes -= bbw;
+ bytes_in_buf -= bbw;
+ dest += bbw;
+ move_pointer(&read_ptr, bbw); //Reset to beginning
+ }
+ memcpy(dest, read_ptr,numBytes);
+ bytes_in_buf -= numBytes;
+ move_pointer(&read_ptr, numBytes);
+ }
+ return 0;
+ }else{
+ return -1;
+ }
+}
+
+int32_t CircBuffer::Write(binary* data, uint32_t length){
+ if(can_write(length)){
+ int32_t bbw = bytes_before_wrap_write();
+ if(bbw >= length){
+ memcpy(write_ptr, data, length);
+ move_pointer(&write_ptr, length);
+ bytes_in_buf += length;
+ }else{
+ if(bbw != 0){
+ memcpy(write_ptr,data,bbw);
+ length -= bbw;
+ bytes_in_buf += bbw;
+ data += bbw;
+ move_pointer(&write_ptr, bbw); //Reset to beginning
+ }
+ memcpy(write_ptr, data,length);
+ bytes_in_buf += length;
+ move_pointer(&write_ptr, length);
+ }
+ return 0;
+ }else{
+ return -1;
+ }
+}
Added: trunk/DvdMenuXtractor/mpegparser/CircBuffer.h
===================================================================
--- trunk/DvdMenuXtractor/mpegparser/CircBuffer.h 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/mpegparser/CircBuffer.h 2005-04-10 12:55:15 UTC (rev 1122)
@@ -0,0 +1,114 @@
+/*****************************************************************************
+
+ Circular/Ring Buffer
+
+ Copyright(C) 2004 John Cannon <[email protected]>
+
+ This program is free software ; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation ; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program ; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ **/
+
+#ifndef __CIRC_BUFFER_H__
+
+#define __CIRC_BUFFER_H__
+
+#include "Types.h"
+
+class CircBuffer {
+private:
+ binary *m_buf;
+ binary *read_ptr;
+ binary *write_ptr;
+
+
+ inline uint32_t bytes_left() {
+ return buf_capacity - bytes_in_buf;
+ }
+
+ inline uint32_t bytes_before_wrap_read() {
+ int32_t a = (int32_t) ((m_buf + buf_capacity) - read_ptr);
+ if(a < 0)
+ return 0;
+ else
+ return a;
+ }
+
+ inline uint32_t bytes_before_wrap_write() {
+ int32_t a = (int32_t)((m_buf + buf_capacity) - write_ptr);
+ if(a < 0)
+ return 0;
+ else
+ return a;
+ }
+
+ inline bool can_write(uint32_t numBytes){
+ return (buf_capacity - bytes_in_buf) >= numBytes;
+ }
+
+ inline bool can_read(uint32_t numBytes){
+ return (bytes_in_buf) >= numBytes;
+ }
+
+ inline void move_pointer(binary** ptr, uint32_t numBytes){
+ *ptr += numBytes;
+ if(((m_buf + buf_capacity) - *ptr) == 0){
+ *ptr = m_buf;
+ //printf("Buffer wrapped\n");
+ }
+ }
+
+public:
+
+ uint32_t buf_capacity;
+ uint32_t bytes_in_buf;
+
+ CircBuffer(uint32_t size);
+ ~CircBuffer();
+
+ const binary* GetReadPtr(){
+ return read_ptr;
+ }
+
+ const binary* GetWritePtr(){
+ return read_ptr;
+ }
+
+ const binary* GetBufPtr(){
+ return read_ptr;
+ }
+
+ binary& operator[](unsigned int i){
+ if(i > bytes_in_buf){
+ return read_ptr[0];
+ }
+ uint32_t bbw = bytes_before_wrap_read();
+ if(i < bbw)
+ return read_ptr[i];
+ else
+ return m_buf[i - bbw];
+ }
+
+ int32_t Read(binary* dest, uint32_t numBytes);
+ int32_t Skip(uint32_t numBytes);
+ int32_t Write(binary* data, uint32_t numBytes);
+
+ uint32_t GetLength(){
+ return bytes_in_buf;
+ }
+
+};
+
+#endif // __CIRC_BUFFER_H__
+
Added: trunk/DvdMenuXtractor/mpegparser/M2VParser.cpp
===================================================================
--- trunk/DvdMenuXtractor/mpegparser/M2VParser.cpp 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/mpegparser/M2VParser.cpp 2005-04-10 12:55:15 UTC (rev 1122)
@@ -0,0 +1,363 @@
+/*****************************************************************************
+
+ MPEG Video Packetizer
+
+ Copyright(C) 2004 John Cannon <[email protected]>
+
+ This program is free software ; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation ; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program ; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ **/
+
+#include "M2VParser.h"
+
+//#include "common.h"
+#define safemalloc(x) malloc(x)
+#define safefree(x) free(x)
+
+#define BUFF_SIZE 2*1024*1024
+
+MPEGFrame::MPEGFrame(binary* data, uint32_t size, bool bCopy){
+ if(bCopy){
+ this->data = (binary *)safemalloc(size);
+ memcpy(this->data, data, size);
+ }else{
+ this->data = data;
+ }
+ this->bCopy = bCopy;
+ this->size = size;
+ firstRef = -1;
+ secondRef = -1;
+}
+
+MPEGFrame::~MPEGFrame(){
+ safefree(data);
+}
+
+void M2VParser::SetEOS(){
+ MPEGChunk * c;
+ while((c = mpgBuf->ReadChunk())){
+ chunks.push_back(c);
+ }
+ mpgBuf->ForceFinal(); //Force the last frame out.
+ c = mpgBuf->ReadChunk();
+ if(c) chunks.push_back(c);
+ FillQueues();
+ m_eos = true;
+}
+
+
+int32_t M2VParser::WriteData(binary* data, uint32_t dataSize){
+ //If we are at EOS
+ if(m_eos)
+ return -1;
+
+ if(mpgBuf->Feed(data, dataSize)){
+ return -1;
+ }
+
+ //Fill the chunks buffer
+ while(mpgBuf->GetState() == MPEG2_BUFFER_STATE_CHUNK_READY){
+ MPEGChunk * c = mpgBuf->ReadChunk();
+ if(c) chunks.push_back(c);
+ }
+
+ if(needInit){
+ if(InitParser() == 0)
+ needInit = false;
+ }
+
+ FillQueues();
+ if(buffers.empty()){
+ parserState = MPV_PARSER_STATE_NEED_DATA;
+ }else{
+ parserState = MPV_PARSER_STATE_FRAME;
+ }
+
+ return 0;
+}
+
+void M2VParser::DumpQueues(){
+ while(!chunks.empty()){
+ delete chunks.front();
+ chunks.erase(chunks.begin());
+ }
+ while(!buffers.empty()){
+ delete buffers.front();
+ buffers.pop();
+ }
+}
+
+/*Fraction ConvertFramerateToFraction(float frameRate){
+ if(frameRate == 24000/1001.0f)
+ return Fraction(24000,1001);
+ else if(frameRate == 30000/1001.0f)
+ return Fraction(30000,1001);
+ else
+ return Fraction(frameRate);
+ }*/
+
+M2VParser::M2VParser(){
+
+ mpgBuf = new MPEGVideoBuffer(BUFF_SIZE);
+
+ notReachedFirstGOP = true;
+ currentStampingTime = 0;
+ position = 0;
+ m_eos = false;
+ mpegVersion = 1;
+ needInit = true;
+ parserState = MPV_PARSER_STATE_NEED_DATA;
+ firstRef = -1;
+ secondRef = -1;
+ nextSkip = -1;
+ nextSkipDuration = -1;
+ seqHdrChunk = NULL;
+}
+
+int32_t M2VParser::InitParser(){
+ //Gotta find a sequence header now
+ MPEGChunk* chunk;
+ //MPEGChunk* seqHdrChunk;
+ for(int 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;
+
+ //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)){
+ mpegVersion = 2;
+ break;
+ }
+ }
+ return 0;
+ }
+ }
+ return -1;
+}
+
+M2VParser::~M2VParser(){
+ DumpQueues();
+ delete seqHdrChunk;
+ delete mpgBuf;
+}
+
+const MediaTime M2VParser::GetPosition(){
+ return position;
+}
+
+MediaTime M2VParser::GetFrameDuration(MPEG2PictureHeader picHdr){
+ if(m_seqHdr.progressiveSequence){
+ if(!picHdr.topFieldFirst && picHdr.repeatFirstField)
+ return 4;
+ else if(picHdr.topFieldFirst && picHdr.repeatFirstField)
+ return 6;
+ else
+ return 2;
+ }
+ if(picHdr.pictureStructure != MPEG2_PICTURE_TYPE_FRAME){
+ return 1;
+ }
+ if(picHdr.progressive && picHdr.repeatFirstField){ //TODO: fix this to support progressive sequences also.
+ return 3;
+ }else{
+ return 2;
+ }
+}
+
+MPEG2ParserState M2VParser::GetState(){
+ FillQueues();
+ if(!buffers.empty())
+ parserState = MPV_PARSER_STATE_FRAME;
+ else
+ parserState = MPV_PARSER_STATE_NEED_DATA;
+
+ if(m_eos && parserState == MPV_PARSER_STATE_NEED_DATA)
+ parserState = MPV_PARSER_STATE_EOS;
+ return parserState;
+}
+
+int32_t M2VParser::CountBFrames(){
+ //We count after the first chunk.
+ int32_t count = 0;
+ if(m_eos) return 0;
+ if(notReachedFirstGOP) return 0;
+ for(int i = 1; i < chunks.size(); i++){
+ MPEGChunk* c = chunks[i];
+ if(c->GetType() == MPEG_VIDEO_PICTURE_START_CODE){
+ MPEG2PictureHeader h = ParsePictureHeader(c);
+ if(h.frameType == MPEG2_B_FRAME){
+ count += GetFrameDuration(h);
+ }else{
+ return count;
+ }
+ }
+ }
+ return -1;
+}
+
+int32_t M2VParser::QueueFrame(MPEGChunk* seqHdr, MPEGChunk* chunk, MediaTime timecode, MPEG2PictureHeader picHdr){
+ MPEGFrame* outBuf;
+ bool bCopy = true;
+ binary* pData = chunk->GetPointer();
+ uint32_t dataLen = chunk->GetSize();
+
+ if(seqHdr){
+ bCopy = false;
+ dataLen += seqHdr->GetSize();
+ pData = (binary *)safemalloc(dataLen);
+ memcpy(pData, seqHdr->GetPointer(), seqHdr->GetSize());
+ memcpy(pData+seqHdr->GetSize(),chunk->GetPointer(), chunk->GetSize());
+ delete seqHdr;
+ seqHdr = NULL;
+ }
+
+ MediaTime duration = GetFrameDuration(picHdr);
+
+ outBuf = new MPEGFrame(pData, dataLen, bCopy);
+
+ if(picHdr.frameType == MPEG2_I_FRAME){
+ outBuf->frameType = 'I';
+ }else if(picHdr.frameType == MPEG2_P_FRAME){
+ outBuf->frameType = 'P';
+ }else{
+ outBuf->frameType = 'B';
+ }
+
+ outBuf->timecode = (MediaTime)(timecode * (1000000000/(m_seqHdr.frameRate*2)));
+ outBuf->duration = (MediaTime)(duration * (1000000000/(m_seqHdr.frameRate*2)));
+
+ if(outBuf->frameType == 'P'){
+ outBuf->firstRef = (MediaTime)(firstRef * (1000000000/(m_seqHdr.frameRate*2)));
+ }else if(outBuf->frameType == 'B'){
+ outBuf->firstRef = (MediaTime)(firstRef * (1000000000/(m_seqHdr.frameRate*2)));
+ outBuf->secondRef = (MediaTime)(secondRef * (1000000000/(m_seqHdr.frameRate*2)));
+ }
+ 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;
+}
+
+void M2VParser::ShoveRef(MediaTime ref){
+ if(firstRef == -1){
+ firstRef = ref;
+ }else if(secondRef == -1){
+ secondRef = ref;
+ }else{
+ firstRef = secondRef;
+ secondRef = ref;
+ }
+}
+
+//Reads frames until it can timestamp them, usually reads until it has
+//an I, P, B+, P...this way it can stamp them all and set references.
+//NOTE: references aren't yet used by our system but they are kept up
+//with in this plugin.
+int32_t M2VParser::FillQueues(){
+ if(chunks.empty()){
+ return -1;
+ }
+ bool done = false;
+ while(!done){
+ MediaTime myTime = currentStampingTime;
+ MPEGChunk* chunk = chunks.front();
+ MPEGChunk* seqHdr = NULL;
+ while(chunk->GetType() != MPEG_VIDEO_PICTURE_START_CODE){
+ if(chunk->GetType() == MPEG_VIDEO_SEQUENCE_START_CODE){
+ if (chunks.size() == 1) return -1;
+ if(seqHdr) delete seqHdr;
+ m_seqHdr = ParseSequenceHeader(chunk);
+ seqHdr = chunk;
+ }else{
+ delete chunk; //Skip all non picture, non seq headers
+ }
+ chunks.erase(chunks.begin());
+ if(chunks.empty()){
+ if(seqHdr != NULL)
+ chunks.push_back(seqHdr);
+ return -1;
+ }
+ chunk = chunks.front();
+ }
+ MPEG2PictureHeader picHdr = ParsePictureHeader(chunk);
+ int bcount;
+ if(myTime == nextSkip){
+ myTime+=nextSkipDuration;
+ currentStampingTime=myTime;
+ }
+ switch(picHdr.frameType){
+ case MPEG2_I_FRAME:
+ bcount = CountBFrames();
+ if(bcount > 0){ //..BBIBB..
+ myTime += bcount;
+ nextSkip = myTime;
+ nextSkipDuration = GetFrameDuration(picHdr);
+ }else{ //IPBB..
+ if(bcount == -1 && !m_eos)
+ return -1;
+ currentStampingTime += GetFrameDuration(picHdr);;
+ }
+ ShoveRef(myTime);
+ QueueFrame(seqHdr,chunk,myTime,picHdr);
+ if(notReachedFirstGOP) notReachedFirstGOP = false;
+ break;
+ case MPEG2_P_FRAME:
+ bcount = CountBFrames();
+ if(firstRef == -1) break;
+ if(bcount > 0){ //..PBB..
+ myTime += bcount;
+ nextSkip = myTime;
+ nextSkipDuration = GetFrameDuration(picHdr);
+ }else{ //..PPBB..
+ if(bcount == -1 && !m_eos) return -1;
+ currentStampingTime+=GetFrameDuration(picHdr);
+ }
+ ShoveRef(myTime);
+ QueueFrame(seqHdr, chunk, myTime, picHdr);
+ break;
+ default: //B-frames
+ if(firstRef == -1 || secondRef == -1) break;
+ QueueFrame(seqHdr,chunk,myTime,picHdr);
+ currentStampingTime+=GetFrameDuration(picHdr);
+ }
+ chunks.erase(chunks.begin());
+ delete chunk;
+ if(chunks.empty()) return -1;
+ }
+ return 0;
+}
+
+MPEGFrame* M2VParser::ReadFrame(){
+ //if(m_eos) return NULL;
+ if(GetState() != MPV_PARSER_STATE_FRAME){
+ return NULL;
+ }
+ if(buffers.empty()){
+ return NULL; // OOPS!
+ }
+ MPEGFrame* frame = buffers.front();
+ buffers.pop();
+ return frame;
+}
+
Added: trunk/DvdMenuXtractor/mpegparser/M2VParser.h
===================================================================
--- trunk/DvdMenuXtractor/mpegparser/M2VParser.h 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/mpegparser/M2VParser.h 2005-04-10 12:55:15 UTC (rev 1122)
@@ -0,0 +1,123 @@
+/*****************************************************************************
+
+ MPEG Video Packetizer
+
+ Copyright(C) 2004 John Cannon <[email protected]>
+
+ This program is free software ; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation ; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program ; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ **/
+
+#ifndef __M2VPARSER_H__
+#define __M2VPARSER_H__
+
+#include "MPEGVideoBuffer.h"
+#include <stdio.h>
+#include <queue>
+
+enum MPEG2ParserState {
+ MPV_PARSER_STATE_FRAME,
+ MPV_PARSER_STATE_NEED_DATA,
+ MPV_PARSER_STATE_EOS,
+ MPV_PARSER_STATE_ERROR
+};
+
+class MPEGFrame {
+public:
+ binary *data;
+ uint32_t size;
+ MediaTime duration;
+ char frameType;
+ MediaTime timecode;
+ MediaTime firstRef;
+ MediaTime secondRef;
+ bool rff;
+ bool tff;
+ bool progressive;
+ uint8_t pictureStructure;
+ bool bCopy;
+
+ MPEGFrame(binary* data, uint32_t size, bool bCopy);
+ ~MPEGFrame();
+};
+
+class M2VParser {
+private:
+ std::vector<MPEGChunk*> chunks; //Hold the chunks until we can stamp them
+ std::queue<MPEGFrame*> buffers; //Holds stamped buffers until they are requested.
+ MediaTime position;
+ //Added to allow reading the header's raw data, contains first found seq hdr.
+ MPEGChunk* seqHdrChunk;
+ MPEG2SequenceHeader m_seqHdr; //current sequence header
+ MediaTime currentStampingTime;
+ MediaTime firstRef;
+ bool needInit;
+ bool m_eos;
+ bool notReachedFirstGOP;
+ MediaTime nextSkip;
+ MediaTime nextSkipDuration;
+ MediaTime secondRef;
+ uint8_t mpegVersion;
+ MPEG2ParserState parserState;
+ MPEGVideoBuffer * mpgBuf;
+
+ int32_t InitParser();
+ void DumpQueues();
+ int32_t FillQueues();
+ int32_t CountBFrames();
+ void ShoveRef(MediaTime ref);
+ MediaTime GetFrameDuration(MPEG2PictureHeader picHdr);
+ int32_t QueueFrame(MPEGChunk* seqHdr, MPEGChunk* chunk, MediaTime timecode, MPEG2PictureHeader picHdr);
+public:
+ M2VParser();
+ virtual ~M2VParser();
+
+ //Returns the current media position
+ virtual const MediaTime GetPosition();
+
+ MPEG2SequenceHeader GetSequenceHeader(){
+ return m_seqHdr;
+ }
+
+ //BE VERY CAREFUL WITH THIS CALL
+ MPEGChunk * GetRealSequenceHeader(){
+ return seqHdrChunk;
+ }
+
+ uint8_t GetMPEGVersion(){
+ return mpegVersion;
+ }
+
+ //Returns a pointer to a frame that has been read
+ virtual MPEGFrame * ReadFrame();
+
+ //Returns the max amount of data that can be written to the buffer
+ int32_t GetFreeBufferSpace(){
+ return mpgBuf->GetFreeBufferSpace();
+ }
+
+ //Writes data to the internal buffer.
+ int32_t WriteData(binary* data, uint32_t dataSize);
+
+ //Returns the current state of the parser
+ MPEG2ParserState GetState();
+
+ //Sets "end of stream" status on the buffer, forces timestamping of frames waiting.
+ //Do not call this without good reason.
+ void SetEOS();
+};
+
+
+#endif //__M2VPARSER_H__
Added: trunk/DvdMenuXtractor/mpegparser/MPEGVideoBuffer.cpp
===================================================================
--- trunk/DvdMenuXtractor/mpegparser/MPEGVideoBuffer.cpp 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/mpegparser/MPEGVideoBuffer.cpp 2005-04-10 12:55:15 UTC (rev 1122)
@@ -0,0 +1,288 @@
+/*****************************************************************************
+
+ MPEG Video Packetizing Buffer
+
+ Copyright(C) 2004 John Cannon <[email protected]>
+
+ This program is free software ; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation ; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program ; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ **/
+
+#include "MPEGVideoBuffer.h"
+#include <stddef.h>
+
+int32_t MPEGVideoBuffer::FindStartCode(uint32_t startPos){
+ //How many bytes can we look through?
+ uint32_t window = myBuffer->GetLength() - startPos;
+
+ if(window < 4) //Make sure we have enough bytes to search.
+ return -1;
+
+ for(unsigned int i = startPos; i < (window - 3); i++){
+ CircBuffer& buf = *myBuffer;
+ binary a,b,c,d;
+ a = buf[i];
+ b = buf[i+1];
+ c = buf[i+2];
+ d = buf[i+3];
+ if((a == 0x00) && (b == 0x00) && (c == 0x01)){
+ switch(d){
+ case MPEG_VIDEO_SEQUENCE_START_CODE:
+ case MPEG_VIDEO_GOP_START_CODE:
+ case MPEG_VIDEO_PICTURE_START_CODE:
+ return i; //Return our position if we found
+ //one of the codes we want
+
+ }
+ }
+ }
+
+ //If we get here we have no _wanted_ start code found.
+ return -1;
+}
+
+void MPEGVideoBuffer::UpdateState(){
+ assert(myBuffer != NULL);
+ int32_t test = 0;
+ if(myBuffer->GetLength() == 0){
+ state = MPEG2_BUFFER_STATE_EMPTY;
+ return;
+ }
+ if(chunkStart == -1){
+ test = FindStartCode(0);
+ if(test != -1) //We found a new startcode
+ chunkStart = test;
+ }
+ if(chunkEnd == -1){
+ test = FindStartCode(chunkStart+4);
+ if(test != -1) //We found a new startcode
+ chunkEnd = test;
+ }
+ if(chunkStart == -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;
+ }
+}
+
+MPEG2BufferState MPEGVideoBuffer::GetState(){
+ return state;
+}
+
+MPEGChunk * MPEGVideoBuffer::ReadChunk(){
+ MPEGChunk* myChunk = NULL;
+ if(state == MPEG2_BUFFER_STATE_CHUNK_READY){
+ assert(chunkStart < chunkEnd && chunkStart != -1 && chunkEnd != -1);
+ if(chunkStart != 0){ //we have to skip some bytes
+ myBuffer->Skip(chunkStart);
+ }
+ uint32_t chunkLength = chunkEnd - chunkStart;
+ binary* chunkData = new binary[chunkLength];
+ myBuffer->Read(chunkData, chunkLength);
+ chunkStart = 0; //we read up to the next start code
+ chunkEnd = -1;
+ UpdateState();
+ myChunk = new MPEGChunk(chunkData, chunkLength);
+ return myChunk;
+ }else{
+ return NULL;
+ }
+}
+
+void MPEGVideoBuffer::ForceFinal(){
+ if(state == MPEG2_BUFFER_STATE_NEED_MORE_DATA){
+ chunkStart = 0;
+ chunkEnd = chunkStart + myBuffer->GetLength();
+ UpdateState();
+ }
+}
+
+int32_t MPEGVideoBuffer::Feed(binary* data, uint32_t numBytes){
+ uint32_t res = myBuffer->Write(data, numBytes);
+ UpdateState();
+ return res;
+}
+
+MPEG2SequenceHeader 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
+ pos+=1;
+ hdr.height = (((unsigned int)pos[0] & 0x0F) << 8) | (((unsigned int) pos[1])); //00 0x xx
+ pos+=2;
+ switch(pos[0] & 0xF0){
+ case 0x10:
+ hdr.aspectRatio = 1.0f;
+ break;
+ case 0x20:
+ hdr.aspectRatio = (4.0f / 3.0f);
+ break;
+ case 0x30:
+ hdr.aspectRatio = (16.0f / 9.0f);
+ //playuing with AR
+ /*pos[0] &=0x0F;
+ pos[0] |= 0x20;*/
+ break;
+ case 0x40:
+ hdr.aspectRatio = 2.21f;
+ break;
+ default:
+ hdr.aspectRatio = -1.0f;
+ }
+ switch(pos[0] & 0x0F){
+ case 0x01:
+ hdr.frameRate = 24000.0f/1001.0f;//23.976
+ break;
+ case 0x02:
+ hdr.frameRate = 24.0f;//24
+ break;
+ case 0x03:
+ hdr.frameRate = 25.0f;//25
+ break;
+ case 0x04:
+ hdr.frameRate = 30000.0f/1001.0f;//29.97
+ //Let's play some more ;)
+ /*pos[0] &= 0xF0; //clear the framerate
+ pos[0] |= 0x01;
+ hdr->frameRate = 24000.0f/1001.0f;//23.976*/
+ break;
+ case 0x05:
+ hdr.frameRate = 30.0f;//30
+ break;
+ case 0x06:
+ hdr.frameRate = 50.0f;//50
+ break;
+ case 0x07:
+ hdr.frameRate = 60000.0f / 1001.0f;//59.94
+ break;
+ case 0x08:
+ hdr.frameRate = 60.0f;//60
+ break;
+ default:
+ hdr.frameRate = 0.0f;
+ }
+
+ //Seek to picturecoding extension
+ while(pos < (chunk->GetPointer() + chunk->GetSize() - 4)){
+ if((pos[0] == 0x00) && (pos[1] == 0x00) && (pos[2] == 0x01) && (pos[3] == MPEG_VIDEO_EXT_START_CODE)){
+ if((pos[4] & 0xF0) == 0x01){ //Picture coding extension
+ //printf("Found a picture_coding_extension\n");
+ haveSeqExt = 1;
+ pos+=4;
+ break;
+ }
+ }
+ pos++;
+ }
+
+ if(haveSeqExt){
+ pos++;
+ hdr.progressiveSequence = (pos[0] & 0x80);
+ }else{
+ hdr.progressiveSequence = 0;
+ }
+
+ return hdr;
+}
+
+MPEG2GOPHeader ParseGOPHeader(MPEGChunk* chunk){
+ MPEG2GOPHeader hdr;
+ binary* pos = chunk->GetPointer();
+ uint32_t timecode;
+ 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;
+ }
+ pos+=4; //skip the startcode
+ //Parse GOP timecode structure
+ timecode = ((uint32_t)pos[0] << 24) |
+ ((uint32_t)pos[1] << 16) |
+ ((uint32_t)pos[2] << 8) |
+ ((uint32_t)pos[3]);
+ hdr.timeHours = (timecode << 1) >> 27;
+ hdr.timeMinutes= (timecode << 6)>>26;
+ hdr.timeSeconds = (timecode << 13) >> 26;
+ hdr.timeFrames = (timecode << 19) >> 26;
+ pos+=3;
+ if(pos[0] & 0x40){ //Check second bit
+ hdr.closedGOP = 1;
+ }else{
+ hdr.closedGOP = 0;
+ }
+ return hdr;
+}
+
+MPEG2PictureHeader ParsePictureHeader(MPEGChunk* chunk){
+ MPEG2PictureHeader hdr;
+ binary* pos = chunk->GetPointer();
+// int i = 0;
+ int havePicExt = 0;
+ uint32_t temp = 0;
+ 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;
+ }
+ pos+=4;
+ temp = (((uint32_t)pos[0]) << 8) | (pos[1] & 0xC0);
+ hdr.temporalReference = temp >> 6;
+ pos+=1;
+ temp = ((uint32_t)(pos[0] & 0x38)) >> 3 ;
+ hdr.frameType = (uint8_t) temp;
+
+ //Seek to picturecoding extension
+ while(pos < (chunk->GetPointer() + chunk->GetSize() - 4)){
+ if((pos[0] == 0x00) && (pos[1] == 0x00) && (pos[2] == 0x01) && (pos[3] == MPEG_VIDEO_EXT_START_CODE)){
+ if((pos[4] & 0xF0) == 0x80){ //Picture coding extension
+ //printf("Found a picture_coding_extension\n");
+ havePicExt = 1;
+ break;
+ }
+ }
+ pos++;
+ }
+ if(!havePicExt){
+ hdr.pictureStructure = MPEG2_PICTURE_TYPE_FRAME;
+ hdr.repeatFirstField = 0;
+ hdr.topFieldFirst = 1;
+ hdr.progressive = 1;
+ }else{
+ pos+=4;//skip start code
+ pos+=2;//skip f_code shit
+ hdr.pictureStructure = (pos[0] & 0x03);
+ pos++;
+ hdr.topFieldFirst = (pos[0] & 0x80);
+ //pos++;
+ hdr.repeatFirstField = (pos[0] & 0x02);
+ /*//let's play ;)
+ hdr->repeatFirstField = (pos[0] = pos[0] & 0xFD) & 0x02;*/
+ pos++;
+ hdr.progressive = (pos[0] & 0x80);
+ }
+
+ return hdr;
+}
Added: trunk/DvdMenuXtractor/mpegparser/MPEGVideoBuffer.h
===================================================================
--- trunk/DvdMenuXtractor/mpegparser/MPEGVideoBuffer.h 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/mpegparser/MPEGVideoBuffer.h 2005-04-10 12:55:15 UTC (rev 1122)
@@ -0,0 +1,155 @@
+/*****************************************************************************
+
+ MPEG Video Packetizing Buffer
+
+ Copyright(C) 2004 John Cannon <[email protected]>
+
+ This program is free software ; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation ; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program ; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ **/
+
+#ifndef __MPEGVIDEOBUFFER_H__
+#define __MPEGVIDEOBUFFER_H__
+
+#include "Types.h"
+#include "CircBuffer.h"
+#include <assert.h>
+
+#define MPEG_VIDEO_PICTURE_START_CODE 0x00
+#define MPEG_VIDEO_SEQUENCE_START_CODE 0xb3
+#define MPEG_VIDEO_EXT_START_CODE 0xb5
+#define MPEG_VIDEO_GOP_START_CODE 0xb8
+#define MPEG_VIDEO_USER_START_CODE 0xb2
+
+enum MPEG2BufferState {
+ 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
+#define MPEG2_B_FRAME 3
+
+typedef struct MPEG2SequenceHeader{
+ uint32_t width;
+ uint32_t height;
+ float aspectRatio;
+ float frameRate;
+ uint8_t progressiveSequence;
+}MPEG2SequenceHeader;
+
+typedef struct MPEG2GOPHeader{
+ uint8_t closedGOP;
+ uint32_t timeFrames;
+ uint32_t timeSeconds;
+ uint32_t timeMinutes;
+ uint32_t timeHours;
+}MPEG2GOPHeader;
+
+#define MPEG2_PICTURE_TYPE_FRAME 0x03
+#define MPEG2_PICTURE_TYPE_TOP_FIELD 0x01
+#define MPEG2_PICTURE_TYPE_BOTTOM_FIELD 0x02
+
+typedef struct MPEG2PictureHeader{
+ uint32_t temporalReference;
+ uint8_t frameType;
+ uint32_t pictureStructure;
+ uint8_t repeatFirstField;
+ uint8_t topFieldFirst;
+ uint8_t progressive;
+}MPEG2PictureHeader;
+
+class MPEGChunk{
+private:
+ binary * data;
+ uint32_t size;
+ uint8_t type;
+public:
+ MPEGChunk(binary* data, uint32_t dataSize){
+ assert(data);
+ this->data = data;
+ assert(dataSize > 4);
+ this->size = dataSize;
+ type = data[3];
+ }
+
+ ~MPEGChunk(){
+ if(data)
+ delete [] data;
+ }
+
+ uint8_t GetType(){
+ return type;
+ }
+
+ uint32_t GetSize(){
+ return size;
+ }
+
+ binary & operator[](unsigned int i){
+ return data[i];
+ }
+
+ binary & at(unsigned int i) {
+ return data[i];
+ }
+
+ binary * GetPointer(){
+ return data;
+ }
+};
+
+MPEG2SequenceHeader ParseSequenceHeader(MPEGChunk* chunk);
+MPEG2PictureHeader ParsePictureHeader(MPEGChunk* chunk);
+MPEG2GOPHeader ParseGOPHeader(MPEGChunk* chunk);
+
+class MPEGVideoBuffer{
+private:
+ CircBuffer * myBuffer;
+ MPEG2BufferState state;
+ int32_t chunkStart;
+ int32_t chunkEnd;
+ void UpdateState();
+ int32_t FindStartCode(uint32_t startPos = 0);
+public:
+ MPEGVideoBuffer(uint32_t size){
+ myBuffer = new CircBuffer(size);
+ state = MPEG2_BUFFER_STATE_EMPTY;
+ chunkStart = -1;
+ chunkEnd = -1;
+ }
+
+ ~MPEGVideoBuffer(){
+ delete myBuffer;
+ }
+
+ MPEG2BufferState GetState();
+
+ int32_t GetFreeBufferSpace(){
+ return (myBuffer->buf_capacity - myBuffer->bytes_in_buf);
+ }
+
+ void SetEndOfData(){
+ chunkEnd = myBuffer->GetLength() - 1;
+ }
+
+ void ForceFinal(); //prepares the remaining data as a chunk
+ MPEGChunk * ReadChunk();
+ int32_t Feed(binary* data, uint32_t numBytes);
+};
+
+#endif //__MPEGVIDEOBUFFER_H__
Added: trunk/DvdMenuXtractor/mpegparser/Types.h
===================================================================
--- trunk/DvdMenuXtractor/mpegparser/Types.h 2005-04-10 08:48:40 UTC (rev 1121)
+++ trunk/DvdMenuXtractor/mpegparser/Types.h 2005-04-10 12:55:15 UTC (rev 1122)
@@ -0,0 +1,9 @@
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+#include <inttypes.h>
+
+typedef int64_t MediaTime;
+typedef uint8_t binary;
+
+#endif // __TYPES_H__
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.