X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=inline;f=src%2FMPEG2_Parser.cpp;h=89abbfd30a790cdcdc498fc30990b6829b0bd551;hb=74e6b1105dffe52c6f347d723507ab346eabbb5a;hp=f6e0089edd3f0d3b09d94ae4f1e7c2aadcaafab0;hpb=9bfe9676115531eb76649e1ebd5e14b904b53ae2;p=asdcplib.git diff --git a/src/MPEG2_Parser.cpp b/src/MPEG2_Parser.cpp index f6e0089..89abbfd 100755 --- a/src/MPEG2_Parser.cpp +++ b/src/MPEG2_Parser.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004, John Hurst +Copyright (c) 2004-2011, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,14 +29,17 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \brief AS-DCP library, MPEG2 raw essence reader implementation */ -#include +#include #include +#include +using Kumu::DefaultLogSink; + using namespace ASDCP; using namespace ASDCP::MPEG2; // data will be read from a VES file in chunks of this size -const ui32_t VESReadSize = 4096; +const ui32_t VESReadSize = 4 * Kumu::Kilobyte; //------------------------------------------------------------------------------------------ @@ -51,6 +54,23 @@ enum ParserState_t { ST_SLICE, }; +const char* +StringParserState(ParserState_t state) +{ + switch ( state ) + { + case ST_INIT: return "INIT"; + case ST_SEQ: return "SEQ"; + case ST_PIC: return "PIC"; + case ST_GOP: return "GOP"; + case ST_EXT: return "EXT"; + case ST_SLICE: return "SLICE"; + } + + return "*UNKNOWN*"; +} + + // class h__ParserState @@ -59,11 +79,11 @@ class h__ParserState ASDCP_NO_COPY_CONSTRUCT(h__ParserState); public: - h__ParserState() : m_State(::ST_INIT) {} + h__ParserState() : m_State(ST_INIT) {} ~h__ParserState() {} - bool Test_SLICE() { return m_State == ST_SLICE; } - void Reset() { m_State = ST_INIT; } + inline bool Test_SLICE() { return m_State == ST_SLICE; } + inline void Reset() { m_State = ST_INIT; } // inline Result_t Goto_SEQ() @@ -71,10 +91,12 @@ class h__ParserState switch ( m_State ) { case ST_INIT: + case ST_EXT: m_State = ST_SEQ; return RESULT_OK; } + DefaultLogSink().Error("SEQ follows %s\n", StringParserState(m_State)); return RESULT_STATE; } @@ -90,6 +112,7 @@ class h__ParserState return RESULT_OK; } + DefaultLogSink().Error("Slice follows %s\n", StringParserState(m_State)); return RESULT_STATE; } @@ -107,23 +130,25 @@ class h__ParserState return RESULT_OK; } + DefaultLogSink().Error("PIC follows %s\n", StringParserState(m_State)); return RESULT_STATE; } // inline Result_t Goto_GOP() - { - switch ( m_State ) - { - case ST_EXT: - case ST_SEQ: - m_State = ST_GOP; - return RESULT_OK; - } - - return RESULT_STATE; - } + { + switch ( m_State ) + { + case ST_EXT: + case ST_SEQ: + m_State = ST_GOP; + return RESULT_OK; + } + + DefaultLogSink().Error("GOP follows %s\n", StringParserState(m_State)); + return RESULT_STATE; + } // inline Result_t Goto_EXT() @@ -138,6 +163,7 @@ class h__ParserState return RESULT_OK; } + DefaultLogSink().Error("EXT follows %s\n", StringParserState(m_State)); return RESULT_STATE; } }; @@ -216,8 +242,8 @@ public: Result_t GOP(VESParser*, const byte_t*, ui32_t) { return RESULT_FALSE; } Result_t Picture(VESParser*, const byte_t*, ui32_t) { return RESULT_FALSE; } - Result_t Slice(VESParser*) { return RESULT_FALSE; } - Result_t Data(VESParser*, const byte_t*, ui32_t) { return RESULT_OK; } + Result_t Slice(VESParser*, byte_t) { return RESULT_FALSE; } + Result_t Data(VESParser*, const byte_t*, i32_t) { return RESULT_OK; } }; @@ -258,7 +284,7 @@ public: m_PlaintextOffset = 0; m_FrameType = FRAME_U; m_State.Reset(); - } + } Result_t Sequence(VESParser*, const byte_t* b, ui32_t s) { @@ -280,17 +306,22 @@ public: return RESULT_FALSE; } - Accessor::Picture PIC(b); - m_TemporalRef = PIC.TemporalRef(); - m_FrameType = PIC.FrameType(); + Accessor::Picture pic(b); + m_TemporalRef = pic.TemporalRef(); + m_FrameType = pic.FrameType(); m_FrameSize += s; return m_State.Goto_PIC(); } - Result_t Slice(VESParser*) + Result_t Slice(VESParser*, byte_t slice_id) { - m_PlaintextOffset = m_FrameSize; - return m_State.Goto_SLICE(); + if ( slice_id == FIRST_SLICE ) + { + m_PlaintextOffset = m_FrameSize; + return m_State.Goto_SLICE(); + } + + return m_State.Test_SLICE() ? RESULT_OK : RESULT_FAIL; } Result_t Extension(VESParser*, const byte_t* b, ui32_t s) @@ -308,7 +339,7 @@ public: return m_State.Goto_GOP(); } - Result_t Data(VESParser*, const byte_t* b, ui32_t s) + Result_t Data(VESParser*, const byte_t* b, i32_t s) { m_FrameSize += s; return RESULT_OK; @@ -324,13 +355,12 @@ public: // - any frame that begins with a picture header is either an I, B or P frame // and is assumed to contain a complete picture header and picture data - class ASDCP::MPEG2::Parser::h__Parser { StreamParams m_ParamsDelegate; FrameParser m_ParserDelegate; VESParser m_Parser; - FileReader m_FileReader; + Kumu::FileReader m_FileReader; ui32_t m_FrameNumber; bool m_EOF; ASDCP::MPEG2::FrameBuffer m_TmpBuffer; @@ -338,10 +368,10 @@ class ASDCP::MPEG2::Parser::h__Parser ASDCP_NO_COPY_CONSTRUCT(h__Parser); public: - h__Parser() : m_TmpBuffer(VESReadSize*2) {} + h__Parser() : m_TmpBuffer(VESReadSize*8) {} ~h__Parser() { Close(); } - Result_t OpenRead(const char* filename); + Result_t OpenRead(const std::string& filename); void Close(); Result_t Reset(); Result_t ReadFrame(FrameBuffer&); @@ -369,9 +399,8 @@ ASDCP::MPEG2::Parser::h__Parser::Close() // ASDCP::Result_t -ASDCP::MPEG2::Parser::h__Parser::OpenRead(const char* filename) +ASDCP::MPEG2::Parser::h__Parser::OpenRead(const std::string& filename) { - ASDCP_TEST_NULL_STR(filename) ui32_t read_count = 0; Result_t result = m_FileReader.OpenRead(filename); @@ -387,9 +416,12 @@ ASDCP::MPEG2::Parser::h__Parser::OpenRead(const char* filename) // Since no one complained and that's the easiest thing to implement, // I have left it that way. Let me know if you want to be able to // locate the first GOP in the stream. - if ( p[0] != 0 || p[1] != 0 || p[2] != 1 ) + ui32_t i = 0; + while ( p[i] == 0 ) i++; + + if ( i < 2 || p[i] != 1 || ! ( p[i+1] == SEQ_START || p[i+1] == PIC_START ) ) { - DefaultLogSink().Error("Frame buffer does not begin with a start code.\n"); + DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n"); return RESULT_RAW_FORMAT; } @@ -402,18 +434,20 @@ ASDCP::MPEG2::Parser::h__Parser::OpenRead(const char* filename) if ( ASDCP_SUCCESS(result) ) { + ui64_t tmp = m_FileReader.Size() / 65536; // a gross approximation + m_ParamsDelegate.m_VDesc.ContainerDuration = (ui32_t) tmp; m_Parser.SetDelegate(&m_ParserDelegate); m_FileReader.Seek(0); } if ( ASDCP_FAILURE(result) ) { - DefaultLogSink().Error("Unable to identify a wrapping mode for the essence in file \"%s\"\n", filename); + DefaultLogSink().Error("Unable to identify a wrapping mode for the essence in file \"%s\"\n", filename.c_str()); m_FileReader.Close(); } - return result; -} + return result;} + // // @@ -434,6 +468,7 @@ ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) // the input file is exhausted. The partial next frame is cached for the // next call. m_ParserDelegate.Reset(); + m_Parser.Reset(); if ( m_TmpBuffer.Size() > 0 ) { @@ -443,18 +478,18 @@ ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) m_TmpBuffer.Size(0); } - while ( ! m_ParserDelegate.m_CompletePicture && ASDCP_SUCCESS(result) ) + while ( ! m_ParserDelegate.m_CompletePicture && result == RESULT_OK ) { if ( FB.Capacity() < ( write_offset + VESReadSize ) ) { - DefaultLogSink().Error("FrameBuf.Capacity: %lu FrameLength: %lu\n", + DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n", FB.Capacity(), ( write_offset + VESReadSize )); return RESULT_SMALLBUF; } result = m_FileReader.Read(FB.Data() + write_offset, VESReadSize, &read_count); - if ( result == RESULT_ENDOFFILE ) + if ( result == RESULT_ENDOFFILE || read_count == 0 ) { m_EOF = true; @@ -471,6 +506,7 @@ ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) if ( m_EOF ) break; } + assert(m_ParserDelegate.m_FrameSize <= write_offset); if ( ASDCP_SUCCESS(result) && m_ParserDelegate.m_FrameSize < write_offset ) @@ -478,21 +514,20 @@ ASDCP::MPEG2::Parser::h__Parser::ReadFrame(FrameBuffer& FB) assert(m_TmpBuffer.Size() == 0); ui32_t diff = write_offset - m_ParserDelegate.m_FrameSize; assert(diff <= m_TmpBuffer.Capacity()); + memcpy(m_TmpBuffer.Data(), FB.RoData() + m_ParserDelegate.m_FrameSize, diff); m_TmpBuffer.Size(diff); } -#ifndef NDEBUG if ( ASDCP_SUCCESS(result) ) { const byte_t* p = FB.RoData(); - if ( p[0] != 0 || p[1] != 0 || p[2] != 1 ) - { - DefaultLogSink().Error("Parsed frame buffer does not begin with a start code.\n"); - return RESULT_RAW_FORMAT; - } + if ( p[0] != 0 || p[1] != 0 || p[2] != 1 || ! ( p[3] == SEQ_START || p[3] == PIC_START ) ) + { + DefaultLogSink().Error("Frame buffer does not begin with a PIC or SEQ start code.\n"); + return RESULT_RAW_FORMAT; + } } -#endif if ( ASDCP_SUCCESS(result) ) { @@ -530,7 +565,7 @@ ASDCP::MPEG2::Parser::~Parser() // Opens the stream for reading, parses enough data to provide a complete // set of stream metadata for the MXFWriter below. ASDCP::Result_t -ASDCP::MPEG2::Parser::OpenRead(const char* filename) const +ASDCP::MPEG2::Parser::OpenRead(const std::string& filename) const { const_cast(this)->m_Parser = new h__Parser; @@ -573,5 +608,5 @@ ASDCP::MPEG2::Parser::FillVideoDescriptor(VideoDescriptor& VDesc) const } // -// end AS_DCP_MPEG2_Parser.cpp +// end MPEG2_Parser.cpp //