1 /* ------------------------------------------------------------------
2  * Copyright (C) 1998-2009 PacketVideo
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13  * express or implied.
14  * See the License for the specific language governing permissions
15  * and limitations under the License.
16  * -------------------------------------------------------------------
17  */
18 #ifndef H263_ONLY
19 
20 #include "mp4def.h"
21 #include "mp4lib_int.h"
22 #include "bitstream_io.h"
23 #include "mp4enc_lib.h"
24 #include "m4venc_oscl.h"
25 
26 /* ======================================================================== */
27 /*  Function : EncodeFrameDataPartMode()                                    */
28 /*  Date     : 09/6/2000                                                    */
29 /*  History  :                                                              */
30 /*  Purpose  : Encode a frame of MPEG4 bitstream in datapartitioning mode.  */
31 /*  In/out   :                                                              */
32 /*  Return   :  PV_SUCCESS if successful else PV_FAIL                       */
33 /*  Modified :                                                              */
34 /*                                                                          */
35 /* ======================================================================== */
EncodeFrameDataPartMode(VideoEncData * video)36 PV_STATUS EncodeFrameDataPartMode(VideoEncData *video)
37 {
38     PV_STATUS status = PV_SUCCESS;
39     Vol *currVol = video->vol[video->currLayer];
40     Vop *currVop = video->currVop;
41     VideoEncParams *encParams = video->encParams;
42     Int width = currVop->width; /* has to be Vop, for multiple of 16 */
43     Int lx = currVop->pitch; /*  with padding */
44     Int offset = 0;
45     Int ind_x, ind_y;
46     Int start_packet_header = 0;
47     UChar *QPMB = video->QPMB;
48     Int QP;
49     Int mbnum = 0, slice_counter = 0;
50     Int num_bits, packet_size = encParams->ResyncPacketsize;
51     BitstreamEncVideo *bs1 = video->bitstream1;
52     BitstreamEncVideo *bs2 = video->bitstream2;
53     BitstreamEncVideo *bs3 = video->bitstream3;
54     Int numHeaderBits;
55     approxDCT fastDCTfunction;
56     Int ncoefblck[6] = {64, 64, 64, 64, 64, 64}; /* for FastCodeMB,  5/18/2001 */
57     PV_STATUS(*CodeMB)(VideoEncData *, approxDCT *, Int, Int[]);
58     void (*MBVlcEncode)(VideoEncData*, Int[], void *);
59     void (*BlockCodeCoeff)(RunLevelBlock*, BitstreamEncVideo*, Int, Int, UChar);
60 
61     video->QP_prev = currVop->quantizer;
62 
63     numHeaderBits = BitstreamGetPos(bs1); /* Number of bits in VOP Header */
64 
65     /* determine type of quantization   */
66 #ifndef NO_MPEG_QUANT
67     if (currVol->quantType == 0)
68         CodeMB = &CodeMB_H263;
69     else
70         CodeMB = &CodeMB_MPEG;
71 #else
72     CodeMB = &CodeMB_H263;
73 #endif
74 
75     /* determine which functions to be used, in MB-level */
76     if (currVop->predictionType == P_VOP)
77         MBVlcEncode = &MBVlcEncodeDataPar_P_VOP;
78     else if (currVop->predictionType == I_VOP)
79         MBVlcEncode = &MBVlcEncodeDataPar_I_VOP;
80     else /* B_VOP not implemented yet */
81         return PV_FAIL;
82 
83     /* determine which VLC table to be used */
84     if (currVol->shortVideoHeader)
85         BlockCodeCoeff = &BlockCodeCoeff_ShortHeader;
86 #ifndef NO_RVLC
87     else if (currVol->useReverseVLC)
88         BlockCodeCoeff = &BlockCodeCoeff_RVLC;
89 #endif
90     else
91         BlockCodeCoeff = &BlockCodeCoeff_Normal;
92 
93     video->usePrevQP = 0;
94 
95     for (ind_y = 0; ind_y < currVol->nMBPerCol; ind_y++)    /* Col MB Loop */
96     {
97 
98         video->outputMB->mb_y = ind_y; /*  5/28/01 */
99 
100         for (ind_x = 0; ind_x < currVol->nMBPerRow; ind_x++)  /* Row MB Loop */
101         {
102             video->outputMB->mb_x = ind_x; /*  5/28/01 */
103             video->mbnum = mbnum;
104             video->sliceNo[mbnum] = slice_counter;      /* Update MB slice number */
105             QP = QPMB[mbnum];   /* always read new QP */
106 
107             /****************************************************************************************/
108             /* MB Prediction:Put into MC macroblock, substract from currVop, put in predMB */
109             /****************************************************************************************/
110 
111             getMotionCompensatedMB(video, ind_x, ind_y, offset);
112 
113             if (start_packet_header)
114             {
115                 slice_counter++;                        /* Increment slice counter */
116                 video->sliceNo[mbnum] = slice_counter;  /* Update MB slice number*/
117                 video->header_bits -= BitstreamGetPos(bs1); /* Header Bits */
118                 video->QP_prev = currVop->quantizer;                        /* store QP */
119                 status = EncodeVideoPacketHeader(video, mbnum, video->QP_prev, 0);
120                 video->header_bits += BitstreamGetPos(bs1); /* Header Bits */
121                 numHeaderBits = BitstreamGetPos(bs1);
122                 start_packet_header = 0;
123                 video->usePrevQP = 0;
124             }
125 
126             /***********************************************/
127             /* Code_MB:  DCT, Q, Q^(-1), IDCT, Motion Comp */
128             /***********************************************/
129 
130             status = (*CodeMB)(video, &fastDCTfunction, (offset << 5) + QP, ncoefblck);
131 
132             /************************************/
133             /* MB VLC Encode: VLC Encode MB     */
134             /************************************/
135 
136             MBVlcEncode(video, ncoefblck, (void*)BlockCodeCoeff);
137 
138             /*************************************************************/
139             /* Assemble Packets:  Assemble the MB VLC codes into Packets */
140             /*************************************************************/
141 
142             /* INCLUDE VOP HEADER IN COUNT */
143 
144             num_bits = BitstreamGetPos(bs1) + BitstreamGetPos(bs2) +
145                        BitstreamGetPos(bs3) - numHeaderBits;
146 
147             /* Assemble_Packet(video) */
148 
149             if (num_bits > packet_size)
150             {
151                 if (video->currVop->predictionType == I_VOP)
152                     BitstreamPutGT16Bits(bs1, 19, DC_MARKER);   /* Add dc_marker */
153                 else
154                     BitstreamPutGT16Bits(bs1, 17, MOTION_MARKER_COMB); /*Add motion_marker*/
155                 BitstreamAppendEnc(bs1, bs2);   /* Combine bs1 and bs2 */
156                 BitstreamAppendEnc(bs1, bs3);   /* Combine bs1 and bs3 */
157                 video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */
158 
159                 status = BitstreamAppendPacket(currVol->stream, bs1); /* Put Packet to Buffer */
160                 /* continue even if status == PV_END_OF_BUF, to get the stats */
161 
162                 BitstreamEncReset(bs1); /* Initialize to 0 */
163                 BitstreamEncReset(bs2);
164                 BitstreamEncReset(bs3);
165                 start_packet_header = 1;
166             }
167             mbnum++;
168             offset += 16;
169         } /* End of For ind_x */
170 
171         offset += (lx << 4) - width;
172     } /* End of For ind_y */
173 
174     if (!start_packet_header)
175     {
176         if (video->currVop->predictionType == I_VOP)
177         {
178             BitstreamPutGT16Bits(bs1, 19, DC_MARKER);   /* Add dc_marker */
179             video->header_bits += 19;
180         }
181         else
182         {
183             BitstreamPutGT16Bits(bs1, 17, MOTION_MARKER_COMB); /* Add motion_marker */
184             video->header_bits += 17;
185         }
186         BitstreamAppendEnc(bs1, bs2);
187         BitstreamAppendEnc(bs1, bs3);
188         video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */
189         status = BitstreamAppendPacket(currVol->stream, bs1); /* Put Packet to Buffer */
190         /* continue even if status == PV_END_OF_BUF, to get the stats */
191         BitstreamEncReset(bs1); /* Initialize to 0 */
192         BitstreamEncReset(bs2);
193         BitstreamEncReset(bs3);
194     }
195 
196     return status; /* if status == PV_END_OF_BUF, this frame will be pre-skipped */
197 }
198 
199 #ifndef  NO_SLICE_ENCODE
200 /* ======================================================================== */
201 /*  Function : EncodeSliceDataPartMode()                                    */
202 /*  Date     : 04/19/2002                                                   */
203 /*  History  :                                                              */
204 /*  Purpose  : Encode a slice of MPEG4 bitstream in DataPar mode and save   */
205 /*              the current MB to continue next time it is called.          */
206 /*  In/out   :                                                              */
207 /*  Return   :  PV_SUCCESS if successful else PV_FAIL                       */
208 /*  Modified :                                                              */
209 /*                                                                          */
210 /* ======================================================================== */
EncodeSliceDataPartMode(VideoEncData * video)211 PV_STATUS EncodeSliceDataPartMode(VideoEncData *video)
212 {
213     PV_STATUS status = PV_SUCCESS;
214     Vol *currVol = video->vol[video->currLayer];
215     Vop *currVop = video->currVop;
216     UChar mode, *Mode = video->headerInfo.Mode;
217     VideoEncParams *encParams = video->encParams;
218     Int nTotalMB = currVol->nTotalMB;
219     Int width = currVop->width; /* has to be Vop, for multiple of 16 */
220     Int lx = currVop->pitch; /* , with pading */
221     UChar *QPMB = video->QPMB;
222     Int QP;
223     Int ind_x = video->outputMB->mb_x, ind_y = video->outputMB->mb_y;
224     Int offset = video->offset;                 /* get current MB location */
225     Int mbnum = video->mbnum, slice_counter = video->sliceNo[mbnum]; /* get current MB location */
226     Int firstMB = mbnum;
227     Int start_packet_header = (mbnum != 0);
228     Int num_bits = 0;
229     Int packet_size = encParams->ResyncPacketsize - 1 - (currVop->predictionType == I_VOP ? 19 : 17);
230     BitstreamEncVideo *bs1 = video->bitstream1;
231     BitstreamEncVideo *bs2 = video->bitstream2;
232     BitstreamEncVideo *bs3 = video->bitstream3;
233     Int bitCount1 = 0, bitCount2 = 0, bitCount3 = 0, byteCount1 = 0, byteCount2 = 0, byteCount3 = 0;
234     Int numHeaderBits = 0;
235     approxDCT fastDCTfunction;
236     Int ncoefblck[6] = {64, 64, 64, 64, 64, 64}; /* for FastCodeMB,  5/18/2001 */
237     UChar CBP;
238     Short outputMB[6][64];
239     PV_STATUS(*CodeMB)(VideoEncData *, approxDCT *, Int, Int[]);
240     void (*MBVlcEncode)(VideoEncData*, Int[], void *);
241     void (*BlockCodeCoeff)(RunLevelBlock*, BitstreamEncVideo*, Int, Int, UChar);
242     Int k;
243 
244     video->QP_prev = 31;
245 
246     if (video->end_of_buf) /* left-over from previous run */
247     {
248         status = BitstreamAppendPacketNoOffset(currVol->stream, bs1);
249         if (status != PV_END_OF_BUF)
250         {
251             BitstreamEncReset(bs1);
252             video->end_of_buf = 0;
253         }
254         return status;
255     }
256 
257     if (mbnum == 0) /* only do this at the start of a frame */
258     {
259         QPMB[0] = video->QP_prev = QP = currVop->quantizer;
260         video->usePrevQP = 0;
261 
262         numHeaderBits = BitstreamGetPos(bs1); /* Number of bits in VOP Header */
263 
264     }
265 
266 
267     /* Re-assign fast functions on every slice, don't have to put it in the memory */
268     QP = QPMB[mbnum];
269     if (mbnum > 0)   video->QP_prev = QPMB[mbnum-1];
270 
271     /* determine type of quantization   */
272 #ifndef NO_MPEG_QUANT
273     if (currVol->quantType == 0)
274         CodeMB = &CodeMB_H263;
275     else
276         CodeMB = &CodeMB_MPEG;
277 #else
278     CodeMB = &CodeMB_H263;
279 #endif
280 
281     /* determine which functions to be used, in MB-level */
282     if (currVop->predictionType == P_VOP)
283         MBVlcEncode = &MBVlcEncodeDataPar_P_VOP;
284     else if (currVop->predictionType == I_VOP)
285         MBVlcEncode = &MBVlcEncodeDataPar_I_VOP;
286     else /* B_VOP not implemented yet */
287         return PV_FAIL;
288 
289     /* determine which VLC table to be used */
290 #ifndef NO_RVLC
291     if (currVol->useReverseVLC)
292         BlockCodeCoeff = &BlockCodeCoeff_RVLC;
293     else
294 #endif
295         BlockCodeCoeff = &BlockCodeCoeff_Normal;
296 
297     if (mbnum != 0)
298     {
299         goto JUMP_IN;
300     }
301 
302     for (ind_y = 0; ind_y < currVol->nMBPerCol; ind_y++)    /* Col MB Loop */
303     {
304 
305         video->outputMB->mb_y = ind_y; /*  5/28/01 */
306 
307         for (ind_x = 0; ind_x < currVol->nMBPerRow; ind_x++)  /* Row MB Loop */
308         {
309 
310             video->outputMB->mb_x = ind_x; /*  5/28/01 */
311             video->mbnum = mbnum;
312             video->sliceNo[mbnum] = slice_counter;      /* Update MB slice number */
313 
314             /****************************************************************************************/
315             /* MB Prediction:Put into MC macroblock, substract from currVop, put in predMB */
316             /****************************************************************************************/
317             getMotionCompensatedMB(video, ind_x, ind_y, offset);
318 
319 JUMP_IN:
320 
321             QP = QPMB[mbnum];   /* always read new QP */
322 
323             if (start_packet_header)
324             {
325                 slice_counter++;                        /* Increment slice counter */
326                 video->sliceNo[mbnum] = slice_counter;  /* Update MB slice number*/
327                 video->QP_prev = currVop->quantizer;                        /* store QP */
328                 num_bits = BitstreamGetPos(bs1);
329                 status = EncodeVideoPacketHeader(video, mbnum, video->QP_prev, 0);
330                 numHeaderBits = BitstreamGetPos(bs1) - num_bits;
331                 video->header_bits += numHeaderBits; /* Header Bits */
332                 start_packet_header = 0;
333                 video->usePrevQP = 0;
334             }
335             else  /* don't encode the first MB in packet again */
336             {
337                 /***********************************************/
338                 /* Code_MB:  DCT, Q, Q^(-1), IDCT, Motion Comp */
339                 /***********************************************/
340 
341                 status = (*CodeMB)(video, &fastDCTfunction, (offset << 5) + QP, ncoefblck);
342                 for (k = 0; k < 6; k++)
343                 {
344                     M4VENC_MEMCPY(outputMB[k], video->outputMB->block[k], sizeof(Short) << 6);
345                 }
346             }
347 
348             /************************************/
349             /* MB VLC Encode: VLC Encode MB     */
350             /************************************/
351 
352             /* save the state before VLC encoding */
353             bitCount1 = BitstreamGetPos(bs1);
354             bitCount2 = BitstreamGetPos(bs2);
355             bitCount3 = BitstreamGetPos(bs3);
356             byteCount1 = bitCount1 >> 3;
357             byteCount2 = bitCount2 >> 3;
358             byteCount3 = bitCount3 >> 3;
359             bitCount1 &= 0x7;
360             bitCount2 &= 0x7;
361             bitCount3 &= 0x7;
362             mode = Mode[mbnum];
363             CBP = video->headerInfo.CBP[mbnum];
364 
365             /*************************************/
366 
367             MBVlcEncode(video, ncoefblck, (void*)BlockCodeCoeff);
368 
369             /*************************************************************/
370             /* Assemble Packets:  Assemble the MB VLC codes into Packets */
371             /*************************************************************/
372 
373             num_bits = BitstreamGetPos(bs1) + BitstreamGetPos(bs2) +
374                        BitstreamGetPos(bs3);// - numHeaderBits; //include header bits
375 
376             /* Assemble_Packet(video) */
377             if (num_bits > packet_size && mbnum != firstMB)  /* encoding at least one more MB*/
378             {
379 
380                 BitstreamRepos(bs1, byteCount1, bitCount1); /* rewind one MB */
381                 BitstreamRepos(bs2, byteCount2, bitCount2); /* rewind one MB */
382                 BitstreamRepos(bs3, byteCount3, bitCount3); /* rewind one MB */
383 
384                 if (video->currVop->predictionType == I_VOP)
385                 {
386                     BitstreamPutGT16Bits(bs1, 19, DC_MARKER);   /* Add dc_marker */
387                     video->header_bits += 19;
388                 }
389                 else
390                 {
391                     BitstreamPutGT16Bits(bs1, 17, MOTION_MARKER_COMB); /*Add motion_marker*/
392                     video->header_bits += 17;
393                 }
394 
395                 status = BitstreamAppendEnc(bs1, bs2);  /* Combine with bs2 */
396                 status = BitstreamAppendEnc(bs1, bs3);  /* Combine with bs3 */
397 
398                 video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */
399                 status = BitstreamAppendPacketNoOffset(currVol->stream, bs1);
400 
401                 BitstreamEncReset(bs2);
402                 BitstreamEncReset(bs3);
403 
404                 if (status == PV_END_OF_BUF) /* if cannot fit a buffer */
405                 {
406                     video->end_of_buf = 1;
407                 }
408                 else
409                 {
410                     BitstreamEncReset(bs1);
411                 }
412 
413                 start_packet_header = 1;
414 
415                 if (mbnum < nTotalMB || video->end_of_buf) /* return here */
416                 {
417                     video->mbnum = mbnum;
418                     video->sliceNo[mbnum] = slice_counter;
419                     video->offset = offset;
420                     Mode[mbnum] = mode;
421                     video->headerInfo.CBP[mbnum] = CBP;
422 
423                     for (k = 0; k < 6; k++)
424                     {
425                         M4VENC_MEMCPY(video->outputMB->block[k], outputMB[k], sizeof(Short) << 6);
426                     }
427 
428                     return status;
429                 }
430             }
431 
432             offset += 16;
433             mbnum++; /* has to increment before SCD, to preserve Mode[mbnum] */
434         } /* End of For ind_x */
435 
436         offset += (lx << 4) - width;
437 
438     } /* End of For ind_y */
439 
440     if (!start_packet_header)
441     {
442         if (video->currVop->predictionType == I_VOP)
443         {
444             BitstreamPutGT16Bits(bs1, 19, DC_MARKER);   /* Add dc_marker */
445             video->header_bits += 19;
446         }
447         else
448         {
449             BitstreamPutGT16Bits(bs1, 17, MOTION_MARKER_COMB); /*Add motion_marker*/
450             video->header_bits += 17;
451         }
452 
453         status = BitstreamAppendEnc(bs1, bs2);  /* Combine with bs2 */
454         status = BitstreamAppendEnc(bs1, bs3);  /* Combine with bs3 */
455 
456         video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */
457         status = BitstreamAppendPacketNoOffset(currVol->stream, bs1);
458 
459         BitstreamEncReset(bs2);
460         BitstreamEncReset(bs3);
461 
462         if (status == PV_END_OF_BUF)
463         {
464             video->end_of_buf = 1;
465         }
466         else
467         {
468             BitstreamEncReset(bs1);
469         }
470     }
471 
472     video->mbnum = mbnum;
473     if (mbnum < nTotalMB)
474         video->sliceNo[mbnum] = slice_counter;
475     video->offset = offset;
476 
477     return status;
478 }
479 #endif /* NO_SLICE_ENCODE */
480 #endif /* H263_ONLY */
481 
482 
483