1 /*****************************************************************************
2 
3     MPEG Video Packetizing Buffer
4 
5     Copyright(C) 2004 John Cannon <spyder@matroska.org>
6 
7     This program is free software ; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation ; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY ; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program ; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
20 
21  **/
22 
23 #pragma once
24 
25 #include "common/common_pch.h"
26 
27 #include "common/math_fwd.h"
28 
29 #include "Types.h"
30 #include "CircBuffer.h"
31 
32 constexpr auto MPEG_VIDEO_PICTURE_START_CODE  = 0x00;
33 constexpr auto MPEG_VIDEO_SEQUENCE_START_CODE = 0xb3;
34 constexpr auto MPEG_VIDEO_EXT_START_CODE      = 0xb5;
35 constexpr auto MPEG_VIDEO_GOP_START_CODE      = 0xb8;
36 constexpr auto MPEG_VIDEO_USER_START_CODE     = 0xb2;
37 
38 enum MPEG2BufferState_e {
39   MPEG2_BUFFER_STATE_NEED_MORE_DATA,
40   MPEG2_BUFFER_STATE_CHUNK_READY,
41   MPEG2_BUFFER_STATE_EMPTY,
42   MPEG2_BUFFER_INVALID
43 };
44 
45 constexpr auto MPEG2_I_FRAME = 1;
46 constexpr auto MPEG2_P_FRAME = 2;
47 constexpr auto MPEG2_B_FRAME = 3;
48 
49 struct MPEG2SequenceHeader {
50   uint32_t width{};
51   uint32_t height{};
52   mtx_mp_rational_t aspectRatio;
53   mtx_mp_rational_t frameRate;
54   uint8_t profileLevelIndication{};
55   uint8_t progressiveSequence{};
56 
57   MPEG2SequenceHeader();
58 };
59 
60 struct MPEG2GOPHeader {
61   uint8_t closedGOP;
62   uint8_t brokenLink;
63   uint32_t timeFrames;
64   uint32_t timeSeconds;
65   uint32_t timeMinutes;
66   uint32_t timeHours;
67 
68   MPEG2GOPHeader();
69 };
70 
71 constexpr auto MPEG2_PICTURE_TYPE_FRAME        = 0x03;
72 constexpr auto MPEG2_PICTURE_TYPE_TOP_FIELD    = 0x01;
73 constexpr auto MPEG2_PICTURE_TYPE_BOTTOM_FIELD = 0x02;
74 
75 struct MPEG2PictureHeader {
76   uint32_t temporalReference;
77   uint8_t frameType;
78   uint32_t pictureStructure;
79   uint8_t repeatFirstField;
80   uint8_t topFieldFirst;
81   uint8_t progressive;
82 
83   MPEG2PictureHeader();
84 };
85 
86 class MPEGChunk{
87 private:
88   binary * data;
89   uint32_t size;
90   uint8_t type;
91 public:
MPEGChunk(binary * n_data,uint32_t n_size)92   MPEGChunk(binary* n_data, uint32_t n_size):
93     data(n_data), size(n_size) {
94 
95     assert(data);
96     assert(4 <= size);
97 
98     type = data[3];
99   }
100 
~MPEGChunk()101   ~MPEGChunk(){
102     if(data)
103       delete [] data;
104   }
105 
GetType()106   inline uint8_t GetType() const {
107     return type;
108   }
109 
GetSize()110   inline uint32_t GetSize() const{
111     return size;
112   }
113 
114   binary & operator[](unsigned int i){
115     return data[i];
116   }
117 
at(unsigned int i)118   binary & at(unsigned int i) {
119     return data[i];
120   }
121 
GetPointer()122   inline binary * GetPointer(){
123     return data;
124   }
125 };
126 
127 void ParseSequenceHeader(MPEGChunk* chunk, MPEG2SequenceHeader & hdr);
128 bool ParsePictureHeader(MPEGChunk* chunk, MPEG2PictureHeader & hdr);
129 bool ParseGOPHeader(MPEGChunk* chunk, MPEG2GOPHeader & hdr);
130 
131 class MPEGVideoBuffer{
132 private:
133   CircBuffer * myBuffer;
134   MPEG2BufferState_e state;
135   int32_t chunkStart;
136   int32_t chunkEnd;
137   void UpdateState();
138   int32_t FindStartCode(uint32_t startPos = 0);
139 public:
MPEGVideoBuffer(uint32_t size)140   MPEGVideoBuffer(uint32_t size){
141     myBuffer = new CircBuffer(size);
142     state = MPEG2_BUFFER_STATE_EMPTY;
143     chunkStart = -1;
144     chunkEnd = -1;
145   }
146 
~MPEGVideoBuffer()147   ~MPEGVideoBuffer(){
148     delete myBuffer;
149   }
150 
GetState()151   inline MPEG2BufferState_e GetState() const { return state; }
152 
GetFreeBufferSpace()153   int32_t GetFreeBufferSpace(){
154     return (myBuffer->buf_capacity - myBuffer->bytes_in_buf);
155   }
156 
SetEndOfData()157   void SetEndOfData(){
158     chunkEnd = myBuffer->GetLength() - 1;
159   }
160 
161   void ForceFinal();  //prepares the remaining data as a chunk
162   MPEGChunk * ReadChunk();
163   int32_t Feed(binary* data, uint32_t numBytes);
164 };
165