/
DVDVideoCodecLibMpeg2.cpp
611 lines (529 loc) · 20.9 KB
/
DVDVideoCodecLibMpeg2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* 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, 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 XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "DVDVideoCodecLibMpeg2.h"
#include "DVDClock.h"
#include "DVDStreamInfo.h"
#include "utils/log.h"
/* I really don't want to include ffmpeg headers here, could */
/* potentially interfere with libmpeg2's, so let's just define this */
#ifndef _LINUX
const int CODEC_ID_MPEG1VIDEO = 1;
#endif
enum MPEGProfile
{
MPEG_422_HL = 0x82,
MPEG_422_ML = 0x52
};
union TagUnion
{
double pts;
struct
{
uint32_t u;
uint32_t l;
} tag;
};
//Decoder specific flags used internal to decoder
#define DVP_FLAG_LIBMPEG2_MASK 0x0000f00
#define DVP_FLAG_LIBMPEG2_ALLOCATED 0x0000100 //Set to indicate that this has allocated data
#define DVP_FLAG_LIBMPEG2_INUSE 0x0000200 //Set to show that libmpeg2 might need to read data from here again
#undef ALIGN
#define ALIGN(value, alignment) (((value)+(alignment-1))&~(alignment-1))
CDVDVideoCodecLibMpeg2::CDVDVideoCodecLibMpeg2()
{
m_pHandle = NULL;
m_pInfo = NULL;
memset(m_pVideoBuffer, 0, sizeof(DVDVideoPicture) * 3);
m_pCurrentBuffer = NULL;
m_irffpattern = 0;
m_bFilm = false;
m_bIs422 = false;
m_dts = DVD_NOPTS_VALUE;
m_dts2 = DVD_NOPTS_VALUE;
}
CDVDVideoCodecLibMpeg2::~CDVDVideoCodecLibMpeg2()
{
Dispose();
}
//This call could possibly be moved outside of the codec, could allow us to do some type of
//direct rendering. problem is that that the buffer requested isn't allways the next one
//that should go to display.
DVDVideoPicture* CDVDVideoCodecLibMpeg2::GetBuffer(unsigned int width, unsigned int height)
{
for(int i = 0; i < 3; i++)
{
if( !(m_pVideoBuffer[i].iFlags & DVP_FLAG_LIBMPEG2_INUSE) )
{
if( m_pVideoBuffer[i].iWidth != width || m_pVideoBuffer[i].iHeight != height ) //Dimensions changed.. realloc needed
{
DeleteBuffer(m_pVideoBuffer+i);
}
if( !(m_pVideoBuffer[i].iFlags & DVP_FLAG_ALLOCATED) )
{ //Need to allocate
//First make sure all properties are reset
memset(&m_pVideoBuffer[i], 0, sizeof(DVDVideoPicture));
//Allocate for YV12 frame
unsigned int iPixels = width*height;
unsigned int iChromaPixels = iPixels/4;
// If we're dealing with a 4:2:2 format, then we actually need more pixels to
// store the chroma, as "the two chroma components are sampled at half the
// sample rate of luma, so horizontal chroma resolution is cut in half."
//
// FIXME: Do we need to handle 4:4:4 and 4:1:1 as well?
//
if (m_bIs422)
iChromaPixels = iPixels/2;
m_pVideoBuffer[i].iLineSize[0] = width; //Y
m_pVideoBuffer[i].iLineSize[1] = width/2; //U
m_pVideoBuffer[i].iLineSize[2] = width/2; //V
m_pVideoBuffer[i].iLineSize[3] = 0;
m_pVideoBuffer[i].iWidth = width;
m_pVideoBuffer[i].iHeight = height;
m_pVideoBuffer[i].data[0] = (BYTE*)_aligned_malloc(iPixels, 16); //Y
m_pVideoBuffer[i].data[1] = (BYTE*)_aligned_malloc(iChromaPixels, 16); //U
m_pVideoBuffer[i].data[2] = (BYTE*)_aligned_malloc(iChromaPixels, 16); //V
//Set all data to 0 for less artifacts.. hmm.. what is black in YUV??
memset( m_pVideoBuffer[i].data[0], 0, iPixels );
memset( m_pVideoBuffer[i].data[1], 0, iChromaPixels );
memset( m_pVideoBuffer[i].data[2], 0, iChromaPixels );
}
m_pVideoBuffer[i].pts = DVD_NOPTS_VALUE;
m_pVideoBuffer[i].iFlags = DVP_FLAG_LIBMPEG2_INUSE | DVP_FLAG_ALLOCATED; //Mark as inuse
return m_pVideoBuffer+i;
}
}
//No free pictures found.
return NULL;
}
void CDVDVideoCodecLibMpeg2::DeleteBuffer(DVDVideoPicture* pPic)
{
if(pPic)
{
_aligned_free(pPic->data[0]);
_aligned_free(pPic->data[1]);
_aligned_free(pPic->data[2]);
pPic->data[0] = 0;
pPic->data[1] = 0;
pPic->data[2] = 0;
pPic->iLineSize[0] = 0;
pPic->iLineSize[1] = 0;
pPic->iLineSize[2] = 0;
pPic->iFlags &= ~DVP_FLAG_ALLOCATED;
pPic->iFlags &= ~DVP_FLAG_LIBMPEG2_ALLOCATED;
if (m_pCurrentBuffer == pPic) m_pCurrentBuffer = NULL;
}
else
{
//Release all buffers
for (int i = 0; i < 3; i++) DeleteBuffer(m_pVideoBuffer + i);
}
}
void CDVDVideoCodecLibMpeg2::ReleaseBuffer(DVDVideoPicture* pPic)
{
if (pPic)
{
pPic->iFlags &= ~DVP_FLAG_LIBMPEG2_INUSE;
}
else
{
//Release all buffers
for (int i = 0; i < 3; i++)
{
m_pVideoBuffer[i].iFlags &= ~DVP_FLAG_LIBMPEG2_INUSE;
}
}
}
bool CDVDVideoCodecLibMpeg2::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
{
if (!m_dll.Load())
return false;
m_dll.mpeg2_accel(MPEG2_ACCEL_X86_MMX);
m_pHandle = m_dll.mpeg2_init();
if (!m_pHandle) return false;
m_pInfo = m_dll.mpeg2_info(m_pHandle);
return true;
}
void CDVDVideoCodecLibMpeg2::Dispose()
{
if (m_pHandle)
m_dll.mpeg2_close(m_pHandle);
m_pHandle = NULL;
m_pInfo = NULL;
DeleteBuffer(NULL);
m_pCurrentBuffer = NULL;
m_irffpattern = 0;
m_dll.Unload();
}
void CDVDVideoCodecLibMpeg2::SetDropState(bool bDrop)
{
m_hurry = bDrop ? 1 : 0;
}
int CDVDVideoCodecLibMpeg2::Decode(BYTE* pData, int iSize, double dts, double pts)
{
int iState = 0;
if (!m_pHandle) return VC_ERROR;
if (pData && iSize)
{
//buffer more data
iState = m_dll.mpeg2_parse(m_pHandle);
if (iState != STATE_BUFFER)
{
CLog::Log(LOGDEBUG,"CDVDVideoCodecLibMpeg2::Decode error, we didn't ask for more data");
return VC_ERROR;
}
// libmpeg2 needs more data. Give it and parse the data again
m_dll.mpeg2_buffer(m_pHandle, pData, pData + iSize);
TagUnion u;
u.pts = pts;
m_dts = dts;
m_dll.mpeg2_tag_picture(m_pHandle, u.tag.l, u.tag.u);
}
iState = m_dll.mpeg2_parse(m_pHandle);
DVDVideoPicture* pBuffer;
// loop until we have another STATE_BUFFER or picture
while (iState != STATE_BUFFER)
{
switch (iState)
{
case STATE_SEQUENCE:
{
// Check for 4:2:2 here.
if (m_pInfo->sequence->profile_level_id == MPEG_422_HL || m_pInfo->sequence->profile_level_id == MPEG_422_ML)
m_bIs422 = true;
//New sequence of frames
//Release all buffers
ReleaseBuffer(NULL);
for (int i = 0; i < 3; i++)
{
//Setup all buffers we wish to use.
pBuffer = GetBuffer(m_pInfo->sequence->width, m_pInfo->sequence->height);
m_dll.mpeg2_set_buf(m_pHandle, pBuffer->data, pBuffer);
}
break;
}
case STATE_GOP:
{
// check for closed captioning or other userdata
if (m_pInfo->user_data && m_pInfo->user_data_len > 0)
{
return VC_USERDATA;
}
break;
}
case STATE_PICTURE:
{
m_dll.mpeg2_skip(m_pHandle, 0);
if(m_hurry>0 && m_pInfo->current_picture)
{
if((m_pInfo->current_picture->flags&PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_B)
m_dll.mpeg2_skip(m_pHandle, 1);
}
m_dts2 = m_dts;
m_dts = DVD_NOPTS_VALUE;
//Not too interesting really
//we can do everything when we get a full picture instead. simplifies things.
//if we want to we could setup the 3rd frame buffer here instead
//but i see no point as of now.
}
break;
case STATE_SLICE:
case STATE_END:
case STATE_INVALID_END:
{
if( m_pInfo->discard_fbuf ) //LIBMPEG2 is done with this buffer, release it
{
if (m_pInfo->discard_fbuf->id)
ReleaseBuffer((DVDVideoPicture*)m_pInfo->discard_fbuf->id);
else
CLog::Log(LOGWARNING, "CDVDVideoCodecLibMpeg2::Decode - libmpeg2 discarded and internal frame");
}
if( m_pInfo->display_fbuf && m_pInfo->display_picture && m_pInfo->sequence )
{
if(m_pInfo->display_fbuf->id)
{
pBuffer = (DVDVideoPicture*)m_pInfo->display_fbuf->id;
pBuffer->iFlags &= ~(DVP_FLAG_REPEAT_TOP_FIELD | DVP_FLAG_TOP_FIELD_FIRST);
pBuffer->iFlags |= (m_pInfo->display_picture->nb_fields > 2) ? DVP_FLAG_REPEAT_TOP_FIELD : 0;
pBuffer->iFlags |= (m_pInfo->display_picture->flags & PIC_FLAG_TOP_FIELD_FIRST) ? DVP_FLAG_TOP_FIELD_FIRST : 0;
//Detection of repeate frame patterns
m_irffpattern = m_irffpattern << 1;
if( pBuffer->iFlags & DVP_FLAG_REPEAT_TOP_FIELD ) m_irffpattern |= 1;
switch (m_pInfo->display_picture->flags & PIC_MASK_CODING_TYPE)
{
case PIC_FLAG_CODING_TYPE_I: pBuffer->iFrameType = FRAME_TYPE_I; break;
case PIC_FLAG_CODING_TYPE_P: pBuffer->iFrameType = FRAME_TYPE_P; break;
case PIC_FLAG_CODING_TYPE_B: pBuffer->iFrameType = FRAME_TYPE_B; break;
case PIC_FLAG_CODING_TYPE_D: pBuffer->iFrameType = FRAME_TYPE_D; break;
default: pBuffer->iFrameType = FRAME_TYPE_UNDEF; break;
}
if(m_pInfo->display_picture->flags & PIC_FLAG_SKIP)
pBuffer->iFlags |= DVP_FLAG_DROPPED;
else
pBuffer->iFlags &= ~DVP_FLAG_DROPPED;
pBuffer->iDuration = m_pInfo->sequence->frame_period;
if( ((m_irffpattern & 0xff) == 0xaa || (m_irffpattern & 0xff) == 0x55) ) /* special case for ntsc 3:2 pulldown */
pBuffer->iRepeatPicture = 0.25;
else if( pBuffer->iFlags & DVP_FLAG_REPEAT_TOP_FIELD )
pBuffer->iRepeatPicture = 0.5 * (m_pInfo->display_picture->nb_fields - 2);
else
pBuffer->iRepeatPicture = 0.0;
//Mpeg frametime is calculated using a 27ghz clock.. pts and such normally a 90mhz clock
pBuffer->iDuration /= (27000000 / DVD_TIME_BASE);
//Figure out of this frame is interlaced
//This is taken from how MPC handles it in Mpeg2DecFilter.cpp. Not sure this is entire correct
//needs to be tested more
//First try to decide if we have film material
if( !(m_pInfo->sequence->flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE)
&& m_pInfo->display_picture->flags & PIC_FLAG_PROGRESSIVE_FRAME)
{ //We have a progressive frame in a nonprogressive sequence
if(!m_bFilm
&& ( ((m_irffpattern & 0xff) == 0xaa || (m_irffpattern & 0xff) == 0x55) ) )
{
//We are not in film mode but we did find a repeat first frame
//Usually means material is in film and 3:2 pullup has been used
//to generate the full ntsc format.
//This also means the frames we get are usually progressive
CLog::Log(LOGDEBUG,"CDVDVideoCodecLibMpeg2::m_bFilm = true\n");
m_bFilm = true;
}
else if(m_bFilm
&& !( ((m_irffpattern & 0xff) == 0xaa || (m_irffpattern & 0xff) == 0x55) ) )
{
//Crap a progressive frame in a nonprogressive sequence that
//doesn't have hte repeat flag set. No idea what format the
//material is in
CLog::Log(LOGDEBUG,"CDVDVideoCodecLibMpeg2::m_bFilm = false\n");
m_bFilm = false;
}
}
// Quoted from MPC Source (Mpeg2DecFilter.cpp)
//// big trouble here, the progressive_frame bit is not reliable :'(
//// frames without temporal field diffs can be only detected when ntsc
//// uses the repeat field flag (signaled with m_fFilm), if it's not set
//// or we have pal then we might end up blending the fields unnecessarily...
if( m_pInfo->sequence->flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE )
{ //We've got a progressive sequence
pBuffer->iFlags &= ~DVP_FLAG_INTERLACED;
}
else if( (m_pInfo->sequence->flags & SEQ_MASK_VIDEO_FORMAT) == SEQ_VIDEO_FORMAT_NTSC || (m_pInfo->sequence->flags & SEQ_MASK_VIDEO_FORMAT) == SEQ_VIDEO_FORMAT_UNSPECIFIED )
{
//This stuff can be quite messy as film based material can be 24 fps progressive
if( m_bFilm )
{ //Film material, not interlaced
pBuffer->iFlags &= ~DVP_FLAG_INTERLACED;
}
else if( (m_pInfo->display_picture->flags & PIC_FLAG_PROGRESSIVE_FRAME) )
{ //This can't allways be trusted, but we let user override
pBuffer->iFlags &= ~DVP_FLAG_INTERLACED;
}
else
{ //Very likely to be interlaced
pBuffer->iFlags |= DVP_FLAG_INTERLACED;
}
}
else
{
//Okey not a progressive sequence and we have no idea if this is really progressive
//have to assume it is not
pBuffer->iFlags |= DVP_FLAG_INTERLACED;
}
pBuffer->iWidth = m_pInfo->sequence->width;
pBuffer->iHeight = m_pInfo->sequence->height;
pBuffer->iDisplayWidth = m_pInfo->sequence->display_width;
pBuffer->iDisplayHeight = m_pInfo->sequence->display_height;
//Try to figure out aspect ratio based on video frame
//in the case of dvd video, we should actually override this
//based on what libdvdnav gives us.
unsigned int pixel_x = m_pInfo->sequence->pixel_width;
unsigned int pixel_y = m_pInfo->sequence->pixel_height;
GuessAspect(m_pInfo->sequence, &pixel_x, &pixel_y);
// modify our displaywidth to suit
float fPixelAR = (float)pixel_x / pixel_y;
pBuffer->iDisplayWidth = (int)((float)pBuffer->iDisplayWidth * fPixelAR);
// make sure we send the color coeficients with the image
pBuffer->color_matrix = m_pInfo->sequence->matrix_coefficients;
pBuffer->color_range = 0; // mpeg2 always have th 16->235/229 color range
pBuffer->chroma_position = 1; // mpeg2 chroma positioning always left
pBuffer->color_primaries = m_pInfo->sequence->colour_primaries;
pBuffer->color_transfer = m_pInfo->sequence->transfer_characteristics;
TagUnion u;
u.tag.l = m_pInfo->display_picture->tag;
u.tag.u = m_pInfo->display_picture->tag2;
pBuffer->pts = u.pts;
pBuffer->dts = m_dts2;
m_dts2 = DVD_NOPTS_VALUE;
// only return this if it's not first image or an I frame
if(m_pCurrentBuffer || pBuffer->iFrameType == FRAME_TYPE_I || pBuffer->iFrameType == FRAME_TYPE_UNDEF )
{
m_pCurrentBuffer = pBuffer;
return VC_PICTURE;
}
}
else
CLog::Log(LOGWARNING, "CDVDVideoCodecLibMpeg2::Decode - libmpeg2 trying to display it's own buffer, skipping...");
}
break;
}
case STATE_INVALID:
{
CLog::Log(LOGDEBUG,"CDVDVideoCodecLibMpeg2::Decode error, invalid state");
// return VC_ERROR;
}
default: break;
}
iState = m_dll.mpeg2_parse(m_pHandle);
}
if (iState == STATE_BUFFER)
return VC_BUFFER;
CLog::Log(LOGDEBUG,"CDVDVideoCodecLibMpeg2::Decode error");
return VC_ERROR;
}
void CDVDVideoCodecLibMpeg2::Reset()
{
/* we can't do a full reset here as then libmpeg2 doesn't search for all *
* start codes, but doesn't have enough state information to continue *
* decoding. m_pHandle->sequence.width should be set to -1 on full reset */
if (m_pHandle)
m_dll.mpeg2_reset(m_pHandle, 0);
ReleaseBuffer(NULL);
m_pCurrentBuffer = NULL;
m_dts = DVD_NOPTS_VALUE;
m_dts2 = DVD_NOPTS_VALUE;
}
bool CDVDVideoCodecLibMpeg2::GetPicture(DVDVideoPicture* pDvdVideoPicture)
{
if(m_pCurrentBuffer && m_pCurrentBuffer->iFlags & DVP_FLAG_ALLOCATED)
{
memcpy(pDvdVideoPicture, m_pCurrentBuffer, sizeof(DVDVideoPicture));
// If we're decoding a 4:2:2 image, we need to skip every other line to get
// down to 4:2:0. We lose image quality, but hopefully nobody will notice.
//
if (m_bIs422)
pDvdVideoPicture->iLineSize[2] <<= 1;
pDvdVideoPicture->format = DVDVideoPicture::FMT_YUV420P;
return true;
}
else
return false;
}
bool CDVDVideoCodecLibMpeg2::GetUserData(DVDVideoUserData* pDvdVideoUserData)
{
if (pDvdVideoUserData && m_pInfo && m_pInfo->user_data && m_pInfo->user_data_len > 0)
{
pDvdVideoUserData->data = (BYTE*)m_pInfo->user_data;
pDvdVideoUserData->size = m_pInfo->user_data_len;
return true;
}
return false;
}
// Redone mpeg2_guess_aspect() code from libmpeg2 (header.c)
// Corrected the pixel ratio compensation as per NTSC/PAL specs.
// This correctly calculates the pixel ratio of sources intended for NTSC or PAL
// screens, and thus we do not need to do any additional compensation within
// the output code. Note that the mpeg2_guess_aspect() code was correct to within 0.1%
// for PAL and 0.3% for NTSC, but we mayaswell be 100% accurate.
int CDVDVideoCodecLibMpeg2::GuessAspect(const mpeg2_sequence_t * sequence,
unsigned int * pixel_width,
unsigned int * pixel_height)
{
static struct
{
unsigned int width, height;
}
video_modes[] = {
{720, 576}, /* 625 lines, 13.5 MHz (D1, DV, DVB, DVD) */
{704, 576}, /* 625 lines, 13.5 MHz (1/1 D1, DVB, DVD, 4CIF) */
{544, 576}, /* 625 lines, 10.125 MHz (DVB, laserdisc) */
{528, 576}, /* 625 lines, 10.125 MHz (3/4 D1, DVB, laserdisc) */
{480, 576}, /* 625 lines, 9 MHz (2/3 D1, DVB, SVCD) */
{352, 576}, /* 625 lines, 6.75 MHz (D2, 1/2 D1, CVD, DVB, DVD) */
{352, 288}, /* 625 lines, 6.75 MHz, 1 field (D4, VCD, DVB, DVD, CIF) */
{176, 144}, /* 625 lines, 3.375 MHz, half field (QCIF) */
{720, 486}, /* 525 lines, 13.5 MHz (D1) */
{704, 486}, /* 525 lines, 13.5 MHz */
{720, 480}, /* 525 lines, 13.5 MHz (DV, DSS, DVD) */
{704, 480}, /* 525 lines, 13.5 MHz (1/1 D1, ATSC, DVD) */
{544, 480}, /* 525 lines. 10.125 MHz (DSS, laserdisc) */
{528, 480}, /* 525 lines. 10.125 MHz (3/4 D1, laserdisc) */
{480, 480}, /* 525 lines, 9 MHz (2/3 D1, SVCD) */
{352, 480}, /* 525 lines, 6.75 MHz (D2, 1/2 D1, CVD, DVD) */
{352, 240} /* 525 lines. 6.75 MHz, 1 field (D4, VCD, DSS, DVD) */
};
unsigned int width, height, pix_width, pix_height, i, DAR_16_9;
*pixel_width = sequence->pixel_width;
*pixel_height = sequence->pixel_height;
width = sequence->picture_width;
height = sequence->picture_height;
for (i = 0; i < sizeof (video_modes) / sizeof (video_modes[0]); i++)
if (width == video_modes[i].width && height == video_modes[i].height)
break;
if (i == sizeof (video_modes) / sizeof (video_modes[0]) ||
(sequence->pixel_width == 1 && sequence->pixel_height == 1) ||
width != sequence->display_width || height != sequence->display_height)
return 0;
for (pix_height = 1; height * pix_height < 480; pix_height <<= 1) {}
height *= pix_height;
for (pix_width = 1; width * pix_width <= 352; pix_width <<= 1) {}
width *= pix_width;
if (! (sequence->flags & SEQ_FLAG_MPEG2))
{
static unsigned int mpeg1_check[2][2] = {{11, 54}, {27, 45}};
DAR_16_9 = (sequence->pixel_height == 27 || sequence->pixel_height == 45);
if (width < 704 || sequence->pixel_height != mpeg1_check[DAR_16_9][height == 576])
return 0;
}
else
{
DAR_16_9 = (3 * sequence->picture_width * sequence->pixel_width >
4 * sequence->picture_height * sequence->pixel_height);
switch (width)
{
case 528:
case 544:
pix_width *= 4;
pix_height *= 3;
break;
case 480:
pix_width *= 3;
pix_height *= 2;
break;
}
}
if (DAR_16_9)
{
pix_width *= 4;
pix_height *= 3;
}
if (height == 576)
{ // we are being pedantic here - the old values are 0.1% out
pix_width *= 128; //59;
pix_height *= 117; //54;
}
else
{ // the old values are 0.3% out
pix_width *= 4320; //10;
pix_height *= 4739; //11;
}
*pixel_width = pix_width;
*pixel_height = pix_height;
// simplify (pixel_width, pixel_height);
return (height == 576) ? 1 : 2;
}