X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FAS_DCP_MPEG2.cpp;h=b7877b54549be8a135afcd77432619bdc55ae2f8;hb=79912d9558b67fb75dfad8bca29d2db1fa58a769;hp=a0a4ad7ff8190f806ba33673f16e34c85b563306;hpb=7a0811d76b7b94909b738336cb94b2d504e7ad18;p=asdcplib.git diff --git a/src/AS_DCP_MPEG2.cpp b/src/AS_DCP_MPEG2.cpp index a0a4ad7..b7877b5 100755 --- a/src/AS_DCP_MPEG2.cpp +++ b/src/AS_DCP_MPEG2.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2007, John Hurst +Copyright (c) 2004-2013, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,6 +30,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "AS_DCP_internal.h" +#include +#include //------------------------------------------------------------------------------------------ @@ -46,7 +48,8 @@ MD_to_MPEG2_VDesc(MXF::MPEG2VideoDescriptor* VDescObj, MPEG2::VideoDescriptor& V VDesc.SampleRate = VDescObj->SampleRate; VDesc.EditRate = VDescObj->SampleRate; VDesc.FrameRate = VDescObj->SampleRate.Numerator; - VDesc.ContainerDuration = VDescObj->ContainerDuration; + assert(VDescObj->ContainerDuration <= 0xFFFFFFFFL); + VDesc.ContainerDuration = (ui32_t) VDescObj->ContainerDuration; VDesc.FrameLayout = VDescObj->FrameLayout; VDesc.StoredWidth = VDescObj->StoredWidth; @@ -59,7 +62,7 @@ MD_to_MPEG2_VDesc(MXF::MPEG2VideoDescriptor* VDescObj, MPEG2::VideoDescriptor& V VDesc.ColorSiting = VDescObj->ColorSiting; VDesc.CodedContentType = VDescObj->CodedContentType; - VDesc.LowDelay = VDescObj->LowDelay == 0 ? false : true; + VDesc.LowDelay = VDescObj->LowDelay.get() == 0 ? false : true; VDesc.BitRate = VDescObj->BitRate; VDesc.ProfileAndLevel = VDescObj->ProfileAndLevel; return RESULT_OK; @@ -92,6 +95,27 @@ MPEG2_VDesc_to_MD(MPEG2::VideoDescriptor& VDesc, MXF::MPEG2VideoDescriptor* VDes return RESULT_OK; } +// +std::ostream& +ASDCP::MPEG2::operator << (std::ostream& strm, const VideoDescriptor& VDesc) +{ + strm << " SampleRate: " << VDesc.SampleRate.Numerator << "/" << VDesc.SampleRate.Denominator << std::endl; + strm << " FrameLayout: " << (unsigned) VDesc.FrameLayout << std::endl; + strm << " StoredWidth: " << (unsigned) VDesc.StoredWidth << std::endl; + strm << " StoredHeight: " << (unsigned) VDesc.StoredHeight << std::endl; + strm << " AspectRatio: " << VDesc.AspectRatio.Numerator << "/" << VDesc.AspectRatio.Denominator << std::endl; + strm << " ComponentDepth: " << (unsigned) VDesc.ComponentDepth << std::endl; + strm << " HorizontalSubsmpl: " << (unsigned) VDesc.HorizontalSubsampling << std::endl; + strm << " VerticalSubsmpl: " << (unsigned) VDesc.VerticalSubsampling << std::endl; + strm << " ColorSiting: " << (unsigned) VDesc.ColorSiting << std::endl; + strm << " CodedContentType: " << (unsigned) VDesc.CodedContentType << std::endl; + strm << " LowDelay: " << (unsigned) VDesc.LowDelay << std::endl; + strm << " BitRate: " << (unsigned) VDesc.BitRate << std::endl; + strm << " ProfileAndLevel: " << (unsigned) VDesc.ProfileAndLevel << std::endl; + strm << " ContainerDuration: " << (unsigned) VDesc.ContainerDuration << std::endl; + + return strm; +} // void @@ -136,45 +160,47 @@ ASDCP::MPEG2::VideoDescriptorDump(const VideoDescriptor& VDesc, FILE* stream) // // hidden, internal implementation of MPEG2 reader -class ASDCP::MPEG2::MXFReader::h__Reader : public ASDCP::h__Reader +class ASDCP::MPEG2::MXFReader::h__Reader : public ASDCP::h__ASDCPReader { ASDCP_NO_COPY_CONSTRUCT(h__Reader); + h__Reader(); public: VideoDescriptor m_VDesc; // video parameter list - h__Reader() {} - ~h__Reader() {} - Result_t OpenRead(const char*); + h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d) {} + virtual ~h__Reader() {} + Result_t OpenRead(const std::string&); Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*); Result_t ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*); Result_t FindFrameGOPStart(ui32_t, ui32_t&); + Result_t FrameType(ui32_t FrameNum, FrameType_t& type); }; // // ASDCP::Result_t -ASDCP::MPEG2::MXFReader::h__Reader::OpenRead(const char* filename) +ASDCP::MPEG2::MXFReader::h__Reader::OpenRead(const std::string& filename) { Result_t result = OpenMXFRead(filename); if( ASDCP_SUCCESS(result) ) { - InterchangeObject* Object; + InterchangeObject* Object = 0; + if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor), &Object)) ) { - assert(Object); + if ( Object == 0 ) + { + DefaultLogSink().Error("MPEG2VideoDescriptor object not found.\n"); + return RESULT_FORMAT; + } + result = MD_to_MPEG2_VDesc((MXF::MPEG2VideoDescriptor*)Object, m_VDesc); } } - if( ASDCP_SUCCESS(result) ) - result = InitMXFIndex(); - - if( ASDCP_SUCCESS(result) ) - result = InitInfo(); - return result; } @@ -209,9 +235,8 @@ ASDCP::MPEG2::MXFReader::h__Reader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& K // look up frame index node IndexTableSegment::IndexEntry TmpEntry; - if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) ) + if ( ASDCP_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) ) { - DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum); return RESULT_RANGE; } @@ -220,6 +245,25 @@ ASDCP::MPEG2::MXFReader::h__Reader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& K return RESULT_OK; } +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::h__Reader::FrameType(ui32_t FrameNum, FrameType_t& type) +{ + if ( ! m_File.IsOpen() ) + return RESULT_INIT; + + // look up frame index node + IndexTableSegment::IndexEntry TmpEntry; + + if ( ASDCP_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) ) + { + return RESULT_RANGE; + } + + type = ( (TmpEntry.Flags & 0x0f) == 3 ) ? FRAME_B : ( (TmpEntry.Flags & 0x0f) == 2 ) ? FRAME_P : FRAME_I; + return RESULT_OK; +} + // // @@ -227,16 +271,17 @@ ASDCP::Result_t ASDCP::MPEG2::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) { + assert(m_Dict); if ( ! m_File.IsOpen() ) return RESULT_INIT; - Result_t result = ReadEKLVPacket(FrameNum, FrameBuf, Dict::ul(MDD_MPEG2Essence), Ctx, HMAC); + Result_t result = ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_MPEG2Essence), Ctx, HMAC); if ( ASDCP_FAILURE(result) ) return result; IndexTableSegment::IndexEntry TmpEntry; - m_FooterPart.Lookup(FrameNum, TmpEntry); + m_IndexAccess.Lookup(FrameNum, TmpEntry); switch ( ( TmpEntry.Flags >> 4 ) & 0x03 ) { @@ -263,7 +308,7 @@ ASDCP::MPEG2::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const if ( stream == 0 ) stream = stderr; - fprintf(stream, "Frame: %06u, %c%-2hu, %7u bytes", + fprintf(stream, "Frame: %06u, %c%-2hhu, %7u bytes", m_FrameNumber, FrameTypeChar(m_FrameType), m_TemporalOffset, m_Size); if ( m_GOPStart ) @@ -280,18 +325,65 @@ ASDCP::MPEG2::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const ASDCP::MPEG2::MXFReader::MXFReader() { - m_Reader = new h__Reader; + m_Reader = new h__Reader(DefaultCompositeDict()); } ASDCP::MPEG2::MXFReader::~MXFReader() { + if ( m_Reader && m_Reader->m_File.IsOpen() ) + m_Reader->Close(); +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OP1aHeader& +ASDCP::MPEG2::MXFReader::OP1aHeader() +{ + if ( m_Reader.empty() ) + { + assert(g_OP1aHeader); + return *g_OP1aHeader; + } + + return m_Reader->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::MPEG2::MXFReader::OPAtomIndexFooter() +{ + if ( m_Reader.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Reader->m_IndexAccess; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::RIP& +ASDCP::MPEG2::MXFReader::RIP() +{ + if ( m_Reader.empty() ) + { + assert(g_RIP); + return *g_RIP; + } + + return m_Reader->m_RIP; } // Open the file for reading. The file must exist. Returns error if the // operation cannot be completed. ASDCP::Result_t -ASDCP::MPEG2::MXFReader::OpenRead(const char* filename) const +ASDCP::MPEG2::MXFReader::OpenRead(const std::string& filename) const { return m_Reader->OpenRead(filename); } @@ -308,6 +400,13 @@ ASDCP::MPEG2::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf, } +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const +{ + return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset); +} + // ASDCP::Result_t ASDCP::MPEG2::MXFReader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf, @@ -374,29 +473,53 @@ void ASDCP::MPEG2::MXFReader::DumpIndex(FILE* stream) const { if ( m_Reader->m_File.IsOpen() ) - m_Reader->m_FooterPart.Dump(stream); + m_Reader->m_IndexAccess.Dump(stream); +} + +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::Close() const +{ + if ( m_Reader && m_Reader->m_File.IsOpen() ) + { + m_Reader->Close(); + return RESULT_OK; + } + + return RESULT_INIT; +} + +// +ASDCP::Result_t +ASDCP::MPEG2::MXFReader::FrameType(ui32_t FrameNum, FrameType_t& type) const +{ + if ( ! m_Reader ) + return RESULT_INIT; + + return m_Reader->FrameType(FrameNum, type); } //------------------------------------------------------------------------------------------ // -class ASDCP::MPEG2::MXFWriter::h__Writer : public ASDCP::h__Writer +class ASDCP::MPEG2::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter { + ASDCP_NO_COPY_CONSTRUCT(h__Writer); + h__Writer(); + public: VideoDescriptor m_VDesc; ui32_t m_GOPOffset; byte_t m_EssenceUL[SMPTE_UL_LENGTH]; - ASDCP_NO_COPY_CONSTRUCT(h__Writer); - - h__Writer() : m_GOPOffset(0) { + h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_GOPOffset(0) { memset(m_EssenceUL, 0, SMPTE_UL_LENGTH); } - ~h__Writer(){} + virtual ~h__Writer(){} - Result_t OpenWrite(const char*, ui32_t HeaderSize); + Result_t OpenWrite(const std::string&, ui32_t HeaderSize); Result_t SetSourceStream(const VideoDescriptor&); Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0); Result_t Finalize(); @@ -406,7 +529,7 @@ public: // Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed. ASDCP::Result_t -ASDCP::MPEG2::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize) +ASDCP::MPEG2::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize) { if ( ! m_State.Test_BEGIN() ) return RESULT_STATE; @@ -416,7 +539,7 @@ ASDCP::MPEG2::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t Heade if ( ASDCP_SUCCESS(result) ) { m_HeaderSize = HeaderSize; - m_EssenceDescriptor = new MPEG2VideoDescriptor; + m_EssenceDescriptor = new MPEG2VideoDescriptor(m_Dict); result = m_State.Goto_INIT(); } @@ -427,24 +550,29 @@ ASDCP::MPEG2::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t Heade ASDCP::Result_t ASDCP::MPEG2::MXFWriter::h__Writer::SetSourceStream(const VideoDescriptor& VDesc) { + assert(m_Dict); if ( ! m_State.Test_INIT() ) return RESULT_STATE; m_VDesc = VDesc; Result_t result = MPEG2_VDesc_to_MD(m_VDesc, (MPEG2VideoDescriptor*)m_EssenceDescriptor); - if ( ASDCP_SUCCESS(result) ) - result = WriteMXFHeader(MPEG_PACKAGE_LABEL, UL(Dict::ul(MDD_MPEG2_VESWrapping)), - PICT_DEF_LABEL, UL(Dict::ul(MDD_PictureDataDef)), - m_VDesc.EditRate, 24 /* TCFrameRate */); - if ( ASDCP_SUCCESS(result) ) { - memcpy(m_EssenceUL, Dict::ul(MDD_MPEG2Essence), SMPTE_UL_LENGTH); + memcpy(m_EssenceUL, m_Dict->ul(MDD_MPEG2Essence), SMPTE_UL_LENGTH); m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container result = m_State.Goto_READY(); } + if ( ASDCP_SUCCESS(result) ) + { + m_FooterPart.SetDeltaParams(IndexTableSegment::DeltaEntry(-1, 0, 0)); + + result = WriteASDCPHeader(MPEG_PACKAGE_LABEL, UL(m_Dict->ul(MDD_MPEG2_VESWrappingFrame)), + PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)), + m_VDesc.EditRate, derive_timecode_rate_from_edit_rate(m_VDesc.EditRate)); + } + return result; } @@ -492,8 +620,15 @@ ASDCP::MPEG2::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESE // update the index manager Entry.TemporalOffset = - FrameBuf.TemporalOffset(); - Entry.KeyFrameOffset = m_GOPOffset; + Entry.KeyFrameOffset = 0 - m_GOPOffset; Entry.Flags = Flags; + /* + fprintf(stderr, "to: %4hd ko: %4hd c1: %4hd c2: %4hd fl: 0x%02x\n", + Entry.TemporalOffset, Entry.KeyFrameOffset, + m_GOPOffset + Entry.TemporalOffset, + Entry.KeyFrameOffset - Entry.TemporalOffset, + Entry.Flags); + */ m_FooterPart.PushIndexEntry(Entry); m_FramesWritten++; m_GOPOffset++; @@ -512,7 +647,7 @@ ASDCP::MPEG2::MXFWriter::h__Writer::Finalize() m_State.Goto_FINAL(); - return WriteMXFFooter(); + return WriteASDCPFooter(); } @@ -528,22 +663,68 @@ ASDCP::MPEG2::MXFWriter::~MXFWriter() { } +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OP1aHeader& +ASDCP::MPEG2::MXFWriter::OP1aHeader() +{ + if ( m_Writer.empty() ) + { + assert(g_OP1aHeader); + return *g_OP1aHeader; + } + + return m_Writer->m_HeaderPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::OPAtomIndexFooter& +ASDCP::MPEG2::MXFWriter::OPAtomIndexFooter() +{ + if ( m_Writer.empty() ) + { + assert(g_OPAtomIndexFooter); + return *g_OPAtomIndexFooter; + } + + return m_Writer->m_FooterPart; +} + +// Warning: direct manipulation of MXF structures can interfere +// with the normal operation of the wrapper. Caveat emptor! +// +ASDCP::MXF::RIP& +ASDCP::MPEG2::MXFWriter::RIP() +{ + if ( m_Writer.empty() ) + { + assert(g_RIP); + return *g_RIP; + } + + return m_Writer->m_RIP; +} // Open the file for writing. The file must not exist. Returns error if // the operation cannot be completed. ASDCP::Result_t -ASDCP::MPEG2::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info, +ASDCP::MPEG2::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info, const VideoDescriptor& VDesc, ui32_t HeaderSize) { - m_Writer = new h__Writer; + if ( Info.LabelSetType == LS_MXF_SMPTE ) + m_Writer = new h__Writer(DefaultSMPTEDict()); + else + m_Writer = new h__Writer(DefaultInteropDict()); + + m_Writer->m_Info = Info; Result_t result = m_Writer->OpenWrite(filename, HeaderSize); if ( ASDCP_SUCCESS(result) ) - { - m_Writer->m_Info = Info; - result = m_Writer->SetSourceStream(VDesc); - } + result = m_Writer->SetSourceStream(VDesc); if ( ASDCP_FAILURE(result) ) m_Writer.release();