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/* ======================================================================== */
36PV_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/* ======================================================================== */
211PV_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
319JUMP_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