1 /***************************************************************************
2 Pulldown : Duplicate frame fields to convert
3 24 fps to 30 fps movie
4
5 1 2 3 4 1 2 3 4 4
6 1 2 3 4 --> 1 2 2 3 4
7
8
9 begin : Thu Mar 21 2002
10 copyright : (C) 2002 by mean
11 email : fixounet@free.fr
12 ***************************************************************************/
13
14 /***************************************************************************
15 * *
16 * This program is free software; you can redistribute it and/or modify *
17 * it under the terms of the GNU General Public License as published by *
18 * the Free Software Foundation; either version 2 of the License, or *
19 * (at your option) any later version. *
20 * *
21 ***************************************************************************/
22
23 #include "ADM_default.h"
24
25 #include "ADM_videoFilterDynamic.h"
26 #include "ADM_vidFieldUtil.h"
27 #include "ADM_interlaced.h"
28 #include "ADM_vidPulldown.h"
29
30 #define aprintf(...) {}
31
32
33 static FILTER_PARAM swapParam={0,{""}};
34 //********** Register chunk ************
35
36 VF_DEFINE_FILTER(ADMVideoPullDown,swapParam,
37 pulldown,
38 QT_TR_NOOP("Pulldown"),
39 1,
40 VF_INTERLACING,
41 QT_TR_NOOP("Convert 24 fps to 30 fps by repeating fields."));
42 //********** Register chunk ************
43
printConf(void)44 char *ADMVideoPullDown::printConf( void )
45 {
46 ADM_FILTER_DECLARE_CONF(" Pulldown");
47
48 }
49 //_______________________________________________________________
ADMVideoPullDown(AVDMGenericVideoStream * in,CONFcouple * setup)50 ADMVideoPullDown::ADMVideoPullDown(
51 AVDMGenericVideoStream *in,CONFcouple *setup)
52 {
53 UNUSED_ARG(setup);
54 _in=in;
55 memcpy(&_info,_in->getInfo(),sizeof(_info));
56 _info.fps1000=(_info.fps1000*5)/4;
57 _info.nb_frames=(_info.nb_frames*5)/4;
58 for(uint32_t i=0;i<5;i++)
59 {
60 _uncompressed[i]=new ADMImage(_info.width,_info.height);
61 }
62 _cacheStart=0xfffffff;
63 }
64 // ___ destructor_____________
~ADMVideoPullDown()65 ADMVideoPullDown::~ADMVideoPullDown()
66 {
67 for(uint32_t i=0;i<5;i++)
68 {
69 delete _uncompressed[i];
70 }
71 }
72
73
getFrameNumberNoAlloc(uint32_t frame,uint32_t * len,ADMImage * data,uint32_t * flags)74 uint8_t ADMVideoPullDown::getFrameNumberNoAlloc(uint32_t frame,
75 uint32_t *len,
76 ADMImage *data,
77 uint32_t *flags)
78 {
79 //static Image in,out;
80 if(frame>=_info.nb_frames)
81 {
82 printf("out of bound frame (%lu / %lu)\n",frame,_info.nb_frames);
83 return 0;
84 }
85
86 uint32_t w=_info.width;
87 uint32_t h=_info.height;
88 uint32_t page=w*h;
89 uint32_t i;
90
91 uint32_t target;
92 uint32_t loop=0;
93
94 *len=(page*3)>>1;
95
96 cont:
97
98 target=frame-((frame)%5);
99 // got it ?
100 if(_cacheStart==target)
101 {
102 uint32_t index;
103
104 aprintf("Filter: It is in cache...(cachestart=%lu)\n",_cacheStart);
105 index=frame%5;
106 aprintf("getting %lu)\n",index);
107 memcpy(YPLANE(data),YPLANE(_uncompressed[index]),page);
108 memcpy(UPLANE(data),UPLANE(_uncompressed[index]),page>>2);
109 memcpy(VPLANE(data),VPLANE(_uncompressed[index]),page>>2);
110 *flags=0;
111 return 1;
112 }
113 else
114 {
115 aprintf("Not in cache...\n");
116 }
117 // Else ask the 5 corresponding frame
118 _cacheStart=target;
119 target=(target*4)/5;
120
121 uint32_t dflags,dlen;
122 #define GET_FRAME(x,y) if(!_in->getFrameNumberNoAlloc(x, &dlen,_uncompressed[y],&dflags)) \
123 {\
124 printf("Cannot get frame %lu\n",x);\
125 return 0; \
126 }
127
128 GET_FRAME(target+0,0);
129 GET_FRAME(target+1,1);
130 GET_FRAME(target+2,3);
131 GET_FRAME(target+3,4);
132 // copy chroma 1->2
133 memcpy(UPLANE(_uncompressed[2]),UPLANE(_uncompressed[1]),page>>2);
134 memcpy(VPLANE(_uncompressed[2]),VPLANE(_uncompressed[1]),page>>2);
135 #define COPY_FIELD \
136 for(uint32_t y=0;y<_info.height>>1;y++) \
137 { \
138 memcpy(out,in,_info.width); \
139 in+=_info.width<<1; \
140 out+=_info.width<<1; \
141 }
142
143 // now we merge 1 & 3 into 2
144
145 uint8_t *in,*out;
146 in=YPLANE(_uncompressed[1]);
147 out=YPLANE(_uncompressed[2]);
148 COPY_FIELD;
149
150
151 // merge 3->2
152 //
153 // 0 1 x 2 3
154 // 0 1 x 2 3
155 //
156 // 0 1 1 2 3
157 // 0 1 X 2 3
158 in=YPLANE(_uncompressed[3])+w;
159 out=YPLANE(_uncompressed[2])+w;
160 COPY_FIELD;
161 // 0 1 1 2 3
162 // 0 1 2 2 3
163 in=YPLANE(_uncompressed[4])+w;
164 out=YPLANE(_uncompressed[3])+w;
165 // 0 1 1 2 3
166 // 0 1 2 3 3
167 COPY_FIELD;
168 goto cont;
169 return 1;
170 }
171
172
173
174