1 /*****************************************************************************
2
3 MPEG Video Packetizer
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 #include "common/common_pch.h"
24 #include "common/memory.h"
25 #include "common/output.h"
26 #include "M2VParser.h"
27
28 constexpr auto BUFF_SIZE = 2 * 1024 * 1024;
29
MPEGFrame(binary * n_data,uint32_t n_size,bool n_bCopy)30 MPEGFrame::MPEGFrame(binary *n_data, uint32_t n_size, bool n_bCopy):
31 size(n_size), bCopy(n_bCopy) {
32
33 if(bCopy) {
34 data = (binary *)safemalloc(size);
35 memcpy(data, n_data, size);
36 } else {
37 data = n_data;
38 }
39 stamped = false;
40 invisible = false;
41 refs[0] = -1;
42 refs[1] = -1;
43 seqHdrData = nullptr;
44 seqHdrDataSize = 0;
45 }
46
~MPEGFrame()47 MPEGFrame::~MPEGFrame(){
48 safefree(data);
49 safefree(seqHdrData);
50 }
51
SetEOS()52 void M2VParser::SetEOS(){
53 MPEGChunk * c;
54 while((c = mpgBuf->ReadChunk())){
55 chunks.push_back(c);
56 }
57 mpgBuf->ForceFinal(); //Force the last frame out.
58 c = mpgBuf->ReadChunk();
59 if(c) chunks.push_back(c);
60 FillQueues();
61 TimestampWaitingFrames();
62 m_eos = true;
63 }
64
65
WriteData(binary * data,uint32_t dataSize)66 int32_t M2VParser::WriteData(binary* data, uint32_t dataSize){
67 //If we are at EOS
68 if(m_eos)
69 return -1;
70
71 if(mpgBuf->Feed(data, dataSize)){
72 return -1;
73 }
74
75 //Fill the chunks buffer
76 while(mpgBuf->GetState() == MPEG2_BUFFER_STATE_CHUNK_READY){
77 MPEGChunk * c = mpgBuf->ReadChunk();
78 if(c) chunks.push_back(c);
79 }
80
81 if(needInit){
82 if(InitParser() == 0)
83 needInit = false;
84 }
85
86 FillQueues();
87 if(buffers.empty()){
88 parserState = MPV_PARSER_STATE_NEED_DATA;
89 }else{
90 parserState = MPV_PARSER_STATE_FRAME;
91 }
92
93 return 0;
94 }
95
DumpQueues()96 void M2VParser::DumpQueues(){
97 while(!chunks.empty()){
98 delete chunks.front();
99 chunks.erase(chunks.begin());
100 }
101 while(!buffers.empty()){
102 delete buffers.front();
103 buffers.pop();
104 }
105 }
106
M2VParser()107 M2VParser::M2VParser()
108 : frameCounter{}
109 , throwOnError{}
110 {
111 mpgBuf = new MPEGVideoBuffer(BUFF_SIZE);
112
113 notReachedFirstGOP = true;
114 previousTimestamp = 0;
115 previousDuration = 0;
116 waitExpectedTime = 0;
117 probing = false;
118 b_frame_warning_printed = false;
119 waitSecondField = false;
120 m_eos = false;
121 mpegVersion = 1;
122 needInit = true;
123 parserState = MPV_PARSER_STATE_NEED_DATA;
124 gopNum = -1;
125 frameNum = 0;
126 gopPts = 0;
127 highestPts = 0;
128 usePictureFrames = false;
129 seqHdrChunk = nullptr;
130 gopChunk = nullptr;
131 keepSeqHdrsInBitstream = true;
132 }
133
InitParser()134 int32_t M2VParser::InitParser(){
135 //Gotta find a sequence header now
136 MPEGChunk* chunk;
137 //MPEGChunk* seqHdrChunk;
138 for (int i = 0, numChunks = chunks.size(); i < numChunks; i++){
139 chunk = chunks[i];
140 if(chunk->GetType() == MPEG_VIDEO_SEQUENCE_START_CODE){
141 //Copy the header for later, we must copy because the actual chunk will be deleted in a bit
142 binary * hdrData = new binary[chunk->GetSize()];
143 memcpy(hdrData, chunk->GetPointer(), chunk->GetSize());
144 seqHdrChunk = new MPEGChunk(hdrData, chunk->GetSize()); //Save this for adding as private data...
145 ParseSequenceHeader(chunk, m_seqHdr);
146
147 //Look for sequence extension to identify mpeg2
148 binary* pData = chunk->GetPointer();
149 for (int j = 3, chunkSize = chunk->GetSize() - 4; j < chunkSize; j++){
150 if(pData[j] == 0x00 && pData[j+1] == 0x00 && pData[j+2] == 0x01 && pData[j+3] == 0xb5 && ((pData[j+4] & 0xF0) == 0x10)){
151 mpegVersion = 2;
152 break;
153 }
154 }
155 return 0;
156 }
157 }
158 return -1;
159 }
160
~M2VParser()161 M2VParser::~M2VParser(){
162 DumpQueues();
163 FlushWaitQueue();
164 delete seqHdrChunk;
165 delete gopChunk;
166 delete mpgBuf;
167 }
168
GetFrameDuration(MPEG2PictureHeader picHdr)169 MediaTime M2VParser::GetFrameDuration(MPEG2PictureHeader picHdr){
170 if (picHdr.repeatFirstField) {
171 // picHdr.progressive shall be 1 if picHdr.repeatFirstField is 1
172 if(m_seqHdr.progressiveSequence)
173 return picHdr.topFieldFirst ? 6 : 4;
174 else
175 return 3;
176 } else {
177 return picHdr.pictureStructure == MPEG2_PICTURE_TYPE_FRAME ? 2 : 1;
178 }
179 }
180
GetState()181 MPEG2ParserState_e M2VParser::GetState(){
182 FillQueues();
183 if(!buffers.empty())
184 parserState = MPV_PARSER_STATE_FRAME;
185 else
186 parserState = MPV_PARSER_STATE_NEED_DATA;
187
188 if(m_eos && parserState == MPV_PARSER_STATE_NEED_DATA)
189 parserState = MPV_PARSER_STATE_EOS;
190 return parserState;
191 }
192
FlushWaitQueue()193 void M2VParser::FlushWaitQueue(){
194 waitSecondField = false;
195
196 for (auto const &frame : waitQueue)
197 delete frame;
198 while (!buffers.empty()) {
199 delete buffers.front();
200 buffers.pop();
201 }
202
203 waitQueue.clear();
204 m_timestamps.clear();
205 }
206
StampFrame(MPEGFrame * frame)207 void M2VParser::StampFrame(MPEGFrame* frame){
208 if (m_timestamps.empty())
209 frame->timestamp = previousTimestamp + previousDuration;
210 else {
211 frame->timestamp = m_timestamps.front();
212 m_timestamps.pop_front();
213 }
214 previousTimestamp = frame->timestamp;
215 frame->duration = mtx::to_int(mtx::rational(frame->duration, 1) * 1'000'000'000 / (m_seqHdr.frameRate * 2));
216 previousDuration = frame->duration;
217
218 frame->stamped = true;
219 frameTimestamps[frame->frameNumber] = frame->timestamp;
220
221 // update affected ref timestamps
222 for (int i = 0; i < 2; i++)
223 if (refs[i].frameNumber == frame->frameNumber)
224 TryUpdate(refs[i]);
225 }
226
UpdateFrame(MPEGFrame * frame)227 void M2VParser::UpdateFrame(MPEGFrame* frame){
228 // derive ref timestamps
229 for (int i = 0; i < 2; i++) {
230 if (!frame->tmpRefs[i].HasFrameNumber())
231 continue;
232 TryUpdate(frame->tmpRefs[i]);
233 assert(frame->tmpRefs[i].HasTimestamp()); // ensure the timestamp indeed has been set (sometime before)
234 frame->refs[i] = frame->tmpRefs[i].timestamp;
235 }
236 }
237
OrderFrame(MPEGFrame * frame)238 int32_t M2VParser::OrderFrame(MPEGFrame* frame){
239 MPEGFrame *p = frame;
240
241 // mxinfo(fmt::format("picStr {0} frame type {1} qt tc {2}\n", p->timestamp, static_cast<int>(p->pictureStructure), p->frameType));
242
243 if (waitSecondField && (p->pictureStructure == MPEG2_PICTURE_TYPE_FRAME)){
244 auto error = Y("Unexpected picture frame after single field frame. Fix the MPEG2 video stream before attempting to multiplex it.\n");
245 if (throwOnError)
246 throw error;
247 mxerror(error);
248 }
249
250 SetFrameRef(p);
251 ShoveRef(p);
252
253 if (('I' == p->frameType) && !waitQueue.empty())
254 TimestampWaitingFrames();
255
256 waitQueue.push_back(p);
257
258 return 0;
259 }
260
261 void
TimestampWaitingFrames()262 M2VParser::TimestampWaitingFrames() {
263 // mxinfo(fmt::format(" flushing {0}\n", waitQueue.size()));
264
265 for (int idx = 0, numFrames = waitQueue.size(); idx < numFrames; ++idx)
266 waitQueue[idx]->decodingOrder = idx;
267
268 std::sort(waitQueue.begin(), waitQueue.end(), [](MPEGFrame *a, MPEGFrame *b) { return a->timestamp < b->timestamp; });
269
270 for (auto const &frame : waitQueue)
271 StampFrame(frame);
272 for (auto const &frame : waitQueue)
273 UpdateFrame(frame);
274
275 std::sort(waitQueue.begin(), waitQueue.end(), [](MPEGFrame *a, MPEGFrame *b) { return a->decodingOrder < b->decodingOrder; });
276
277 for (auto const &frame : waitQueue)
278 buffers.push(frame);
279 waitQueue.clear();
280 }
281
PrepareFrame(MPEGChunk * chunk,MediaTime timestamp,MPEG2PictureHeader picHdr)282 int32_t M2VParser::PrepareFrame(MPEGChunk* chunk, MediaTime timestamp, MPEG2PictureHeader picHdr){
283 MPEGFrame* outBuf;
284 bool bCopy = true;
285 binary* pData = chunk->GetPointer();
286 uint32_t dataLen = chunk->GetSize();
287
288 if ((seqHdrChunk && keepSeqHdrsInBitstream &&
289 (MPEG2_I_FRAME == picHdr.frameType)) || gopChunk) {
290 uint32_t pos = 0;
291 bCopy = false;
292 dataLen +=
293 (seqHdrChunk && keepSeqHdrsInBitstream && (MPEG2_I_FRAME == picHdr.frameType) ? seqHdrChunk->GetSize() : 0) +
294 (gopChunk ? gopChunk->GetSize() : 0);
295 pData = (binary *)safemalloc(dataLen);
296 if (seqHdrChunk && keepSeqHdrsInBitstream &&
297 (MPEG2_I_FRAME == picHdr.frameType)) {
298 memcpy(pData, seqHdrChunk->GetPointer(), seqHdrChunk->GetSize());
299 pos += seqHdrChunk->GetSize();
300 delete seqHdrChunk;
301 seqHdrChunk = nullptr;
302 }
303 if (gopChunk) {
304 memcpy(pData + pos, gopChunk->GetPointer(), gopChunk->GetSize());
305 pos += gopChunk->GetSize();
306 delete gopChunk;
307 gopChunk = nullptr;
308 }
309 memcpy(pData + pos, chunk->GetPointer(), chunk->GetSize());
310 }
311
312 outBuf = new MPEGFrame(pData, dataLen, bCopy);
313 outBuf->frameNumber = frameCounter++;
314
315 if (seqHdrChunk && !keepSeqHdrsInBitstream &&
316 (MPEG2_I_FRAME == picHdr.frameType)) {
317 outBuf->seqHdrData = (binary *)safemalloc(seqHdrChunk->GetSize());
318 outBuf->seqHdrDataSize = seqHdrChunk->GetSize();
319 memcpy(outBuf->seqHdrData, seqHdrChunk->GetPointer(),
320 outBuf->seqHdrDataSize);
321 delete seqHdrChunk;
322 seqHdrChunk = nullptr;
323 }
324
325 if(picHdr.frameType == MPEG2_I_FRAME){
326 outBuf->frameType = 'I';
327 }else if(picHdr.frameType == MPEG2_P_FRAME){
328 outBuf->frameType = 'P';
329 }else{
330 outBuf->frameType = 'B';
331 }
332
333 outBuf->timestamp = timestamp; // Still the sequence number
334
335 outBuf->invisible = invisible;
336 outBuf->duration = GetFrameDuration(picHdr);
337 outBuf->rff = (picHdr.repeatFirstField != 0);
338 outBuf->tff = (picHdr.topFieldFirst != 0);
339 outBuf->progressive = (picHdr.progressive != 0);
340 outBuf->pictureStructure = (uint8_t) picHdr.pictureStructure;
341
342 OrderFrame(outBuf);
343 return 0;
344 }
345
SetFrameRef(MPEGFrame * ref)346 void M2VParser::SetFrameRef(MPEGFrame *ref){
347 if (ref->frameType == 'B') {
348 ref->tmpRefs[0] = refs[0];
349 ref->tmpRefs[1] = refs[1];
350 } else if(ref->frameType == 'P')
351 ref->tmpRefs[0] = refs[1];
352 }
353
ShoveRef(MPEGFrame * ref)354 void M2VParser::ShoveRef(MPEGFrame *ref){
355 if(ref->frameType == 'I' || ref->frameType == 'P'){
356 refs[0] = refs[1];
357 refs[1].Clear();
358 refs[1].frameNumber = ref->frameNumber;
359 }
360 }
361
ClearRef()362 void M2VParser::ClearRef(){
363 for (int i = 0; i < 2; i++)
364 refs[i].Clear();
365 }
366
367 //Maintains the time of the last start of GOP and uses the temporal_reference
368 //field as an offset.
FillQueues()369 int32_t M2VParser::FillQueues(){
370 if(chunks.empty()){
371 return -1;
372 }
373 bool done = false;
374 while(!done){
375 MediaTime myTime;
376 MPEGChunk* chunk = chunks.front();
377 while (chunk->GetType() != MPEG_VIDEO_PICTURE_START_CODE) {
378 if (chunk->GetType() == MPEG_VIDEO_GOP_START_CODE) {
379 ParseGOPHeader(chunk, m_gopHdr);
380 if (frameNum != 0) {
381 gopPts = highestPts + 1;
382 }
383 if (gopChunk)
384 delete gopChunk;
385 gopChunk = chunk;
386 gopNum++;
387 /* Perform some sanity checks */
388 if(waitSecondField){
389 auto error = Y("Single field frame before GOP header detected. Fix the MPEG2 video stream before attempting to multiplex it.\n");
390 if (throwOnError)
391 throw error;
392 mxerror(error);
393 }
394 // There are too many broken videos to do the following so ReferenceBlock will be wrong for broken videos.
395 /*
396 if(m_gopHdr.closedGOP){
397 ClearRef();
398 }
399 */
400 } else if (chunk->GetType() == MPEG_VIDEO_SEQUENCE_START_CODE) {
401 if (seqHdrChunk)
402 delete seqHdrChunk;
403 ParseSequenceHeader(chunk, m_seqHdr);
404 seqHdrChunk = chunk;
405
406 }
407
408 chunks.erase(chunks.begin());
409 if (chunks.empty())
410 return -1;
411 chunk = chunks.front();
412 }
413 MPEG2PictureHeader picHdr;
414 ParsePictureHeader(chunk, picHdr);
415
416 if (picHdr.pictureStructure == MPEG2_PICTURE_TYPE_FRAME) {
417 usePictureFrames = true;
418 }
419 myTime = gopPts + picHdr.temporalReference;
420 invisible = false;
421
422 if (myTime > highestPts)
423 highestPts = myTime;
424
425 switch(picHdr.frameType){
426 case MPEG2_I_FRAME:
427 PrepareFrame(chunk, myTime, picHdr);
428 notReachedFirstGOP = false;
429 break;
430 case MPEG2_P_FRAME:
431 if (!refs[1].HasFrameNumber())
432 break;
433 PrepareFrame(chunk, myTime, picHdr);
434 break;
435 default: //B-frames
436 if (!refs[0].HasFrameNumber() || !refs[1].HasFrameNumber()) {
437 if (!m_gopHdr.closedGOP && !m_gopHdr.brokenLink && !probing && !b_frame_warning_printed) {
438 mxwarn(Y("Found at least one B frame without second reference in a non closed GOP.\n"));
439 b_frame_warning_printed = true;
440 }
441 invisible = true;
442 }
443 PrepareFrame(chunk, myTime, picHdr);
444 }
445 frameNum++;
446 chunks.erase(chunks.begin());
447 delete chunk;
448 if (chunks.empty())
449 return -1;
450 }
451 return 0;
452 }
453
ReadFrame()454 MPEGFrame* M2VParser::ReadFrame(){
455 //if(m_eos) return nullptr;
456 if(GetState() != MPV_PARSER_STATE_FRAME){
457 return nullptr;
458 }
459 if(buffers.empty()){
460 return nullptr; // OOPS!
461 }
462 MPEGFrame* frame = buffers.front();
463 buffers.pop();
464 return frame;
465 }
466
467 void
AddTimestamp(int64_t timestamp)468 M2VParser::AddTimestamp(int64_t timestamp) {
469 std::list<int64_t>::iterator idx = m_timestamps.begin();
470 while ((idx != m_timestamps.end()) && (timestamp > *idx))
471 idx++;
472 m_timestamps.insert(idx, timestamp);
473 }
474
475 void
SetThrowOnError(bool doThrow)476 M2VParser::SetThrowOnError(bool doThrow) {
477 throwOnError = doThrow;
478 }
479
480 void
TryUpdate(MPEGFrameRef & frame)481 M2VParser::TryUpdate(MPEGFrameRef &frame){
482 // if frame set, stamped and no timestamp yet, derive it
483 if (frame.HasTimestamp() || !frame.HasFrameNumber())
484 return;
485
486 auto itr = frameTimestamps.find(frame.frameNumber);
487 if (itr != frameTimestamps.end())
488 frame.timestamp = itr->second;
489 }
490