1/*
2 * Copyright (C) 2009 The Android Open Source Project
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 express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "H264SwDecApi.h"
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22/*------------------------------------------------------------------------------
23    Module defines
24------------------------------------------------------------------------------*/
25
26/* CHECK_MEMORY_USAGE prints and sums the memory allocated in calls to
27 * H264SwDecMalloc() */
28/* #define CHECK_MEMORY_USAGE */
29
30/* _NO_OUT disables output file writing */
31/* #define _NO_OUT */
32
33/* Debug prints */
34#define DEBUG(argv) printf argv
35
36/* CVS tag name for identification */
37const char tagName[256] = "$Name: FIRST_ANDROID_COPYRIGHT $";
38
39void WriteOutput(char *filename, u8 *data, u32 picSize);
40u32 NextPacket(u8 **pStrm);
41u32 CropPicture(u8 *pOutImage, u8 *pInImage,
42    u32 picWidth, u32 picHeight, CropParams *pCropParams);
43
44/* Global variables for stream handling */
45u8 *streamStop = NULL;
46u32 packetize = 0;
47u32 nalUnitStream = 0;
48FILE *foutput = NULL;
49
50#ifdef SOC_DESIGNER
51
52// Initialisation function defined in InitCache.s
53extern void cache_init(void);
54
55/*------------------------------------------------------------------------------
56
57    Function name:  $Sub$$main
58
59    Purpose:
60        This function is called at the end of the C library initialisation and
61        before main. Its purpose is to do any further initialisation before the
62        application start.
63
64------------------------------------------------------------------------------*/
65int $Sub$$main(char argc, char * argv[])
66{
67  cache_init();                    // does some extra setup work setting up caches
68  return $Super$$main(argc, argv); // calls the original function
69}
70#endif
71
72/*------------------------------------------------------------------------------
73
74    Function name:  main
75
76    Purpose:
77        main function of decoder testbench. Provides command line interface
78        with file I/O for H.264 decoder. Prints out the usage information
79        when executed without arguments.
80
81------------------------------------------------------------------------------*/
82
83int main(int argc, char **argv)
84{
85
86    u32 i, tmp;
87    u32 maxNumPics = 0;
88    u8 *byteStrmStart;
89    u8 *imageData;
90    u8 *tmpImage = NULL;
91    u32 strmLen;
92    u32 picSize;
93    H264SwDecInst decInst;
94    H264SwDecRet ret;
95    H264SwDecInput decInput;
96    H264SwDecOutput decOutput;
97    H264SwDecPicture decPicture;
98    H264SwDecInfo decInfo;
99    H264SwDecApiVersion decVer;
100    u32 picDecodeNumber;
101    u32 picDisplayNumber;
102    u32 numErrors = 0;
103    u32 cropDisplay = 0;
104    u32 disableOutputReordering = 0;
105
106    FILE *finput;
107
108    char outFileName[256] = "";
109
110    /* Print API version number */
111    decVer = H264SwDecGetAPIVersion();
112    DEBUG(("H.264 Decoder API v%d.%d\n", decVer.major, decVer.minor));
113
114    /* Print tag name if '-T' argument present */
115    if ( argc > 1 && strcmp(argv[1], "-T") == 0 )
116    {
117        DEBUG(("%s\n", tagName));
118        return 0;
119    }
120
121    /* Check that enough command line arguments given, if not -> print usage
122     * information out */
123    if (argc < 2)
124    {
125        DEBUG((
126            "Usage: %s [-Nn] [-Ooutfile] [-P] [-U] [-C] [-R] [-T] file.h264\n",
127            argv[0]));
128        DEBUG(("\t-Nn forces decoding to stop after n pictures\n"));
129#if defined(_NO_OUT)
130        DEBUG(("\t-Ooutfile output writing disabled at compile time\n"));
131#else
132        DEBUG(("\t-Ooutfile write output to \"outfile\" (default out_wxxxhyyy.yuv)\n"));
133        DEBUG(("\t-Onone does not write output\n"));
134#endif
135        DEBUG(("\t-P packet-by-packet mode\n"));
136        DEBUG(("\t-U NAL unit stream mode\n"));
137        DEBUG(("\t-C display cropped image (default decoded image)\n"));
138        DEBUG(("\t-R disable DPB output reordering\n"));
139        DEBUG(("\t-T to print tag name and exit\n"));
140        return 0;
141    }
142
143    /* read command line arguments */
144    for (i = 1; i < (u32)(argc-1); i++)
145    {
146        if ( strncmp(argv[i], "-N", 2) == 0 )
147        {
148            maxNumPics = (u32)atoi(argv[i]+2);
149        }
150        else if ( strncmp(argv[i], "-O", 2) == 0 )
151        {
152            strcpy(outFileName, argv[i]+2);
153        }
154        else if ( strcmp(argv[i], "-P") == 0 )
155        {
156            packetize = 1;
157        }
158        else if ( strcmp(argv[i], "-U") == 0 )
159        {
160            nalUnitStream = 1;
161        }
162        else if ( strcmp(argv[i], "-C") == 0 )
163        {
164            cropDisplay = 1;
165        }
166        else if ( strcmp(argv[i], "-R") == 0 )
167        {
168            disableOutputReordering = 1;
169        }
170    }
171
172    /* open input file for reading, file name given by user. If file open
173     * fails -> exit */
174    finput = fopen(argv[argc-1],"rb");
175    if (finput == NULL)
176    {
177        DEBUG(("UNABLE TO OPEN INPUT FILE\n"));
178        return -1;
179    }
180
181    /* check size of the input file -> length of the stream in bytes */
182    fseek(finput,0L,SEEK_END);
183    strmLen = (u32)ftell(finput);
184    rewind(finput);
185
186    /* allocate memory for stream buffer. if unsuccessful -> exit */
187    byteStrmStart = (u8 *)malloc(sizeof(u8)*strmLen);
188    if (byteStrmStart == NULL)
189    {
190        DEBUG(("UNABLE TO ALLOCATE MEMORY\n"));
191        return -1;
192    }
193
194    /* read input stream from file to buffer and close input file */
195    fread(byteStrmStart, sizeof(u8), strmLen, finput);
196    fclose(finput);
197
198    /* initialize decoder. If unsuccessful -> exit */
199    ret = H264SwDecInit(&decInst, disableOutputReordering);
200    if (ret != H264SWDEC_OK)
201    {
202        DEBUG(("DECODER INITIALIZATION FAILED\n"));
203        free(byteStrmStart);
204        return -1;
205    }
206
207    /* initialize H264SwDecDecode() input structure */
208    streamStop = byteStrmStart + strmLen;
209    decInput.pStream = byteStrmStart;
210    decInput.dataLen = strmLen;
211    decInput.intraConcealmentMethod = 0;
212
213    /* get pointer to next packet and the size of packet
214     * (for packetize or nalUnitStream modes) */
215    if ( (tmp = NextPacket(&decInput.pStream)) != 0 )
216        decInput.dataLen = tmp;
217
218    picDecodeNumber = picDisplayNumber = 1;
219    /* main decoding loop */
220    do
221    {
222        /* Picture ID is the picture number in decoding order */
223        decInput.picId = picDecodeNumber;
224
225        /* call API function to perform decoding */
226        ret = H264SwDecDecode(decInst, &decInput, &decOutput);
227
228        switch(ret)
229        {
230
231            case H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY:
232                /* Stream headers were successfully decoded
233                 * -> stream information is available for query now */
234
235                ret = H264SwDecGetInfo(decInst, &decInfo);
236                if (ret != H264SWDEC_OK)
237                    return -1;
238
239                DEBUG(("Profile %d\n", decInfo.profile));
240
241                DEBUG(("Width %d Height %d\n",
242                    decInfo.picWidth, decInfo.picHeight));
243
244                if (cropDisplay && decInfo.croppingFlag)
245                {
246                    DEBUG(("Cropping params: (%d, %d) %dx%d\n",
247                        decInfo.cropParams.cropLeftOffset,
248                        decInfo.cropParams.cropTopOffset,
249                        decInfo.cropParams.cropOutWidth,
250                        decInfo.cropParams.cropOutHeight));
251
252                    /* Cropped frame size in planar YUV 4:2:0 */
253                    picSize = decInfo.cropParams.cropOutWidth *
254                              decInfo.cropParams.cropOutHeight;
255                    picSize = (3 * picSize)/2;
256                    tmpImage = malloc(picSize);
257                    if (tmpImage == NULL)
258                        return -1;
259                }
260                else
261                {
262                    /* Decoder output frame size in planar YUV 4:2:0 */
263                    picSize = decInfo.picWidth * decInfo.picHeight;
264                    picSize = (3 * picSize)/2;
265                }
266
267                DEBUG(("videoRange %d, matrixCoefficients %d\n",
268                    decInfo.videoRange, decInfo.matrixCoefficients));
269
270                /* update H264SwDecDecode() input structure, number of bytes
271                 * "consumed" is computed as difference between the new stream
272                 * pointer and old stream pointer */
273                decInput.dataLen -=
274                    (u32)(decOutput.pStrmCurrPos - decInput.pStream);
275                decInput.pStream = decOutput.pStrmCurrPos;
276
277                /* If -O option not used, generate default file name */
278                if (outFileName[0] == 0)
279                    sprintf(outFileName, "out_w%dh%d.yuv",
280                            decInfo.picWidth, decInfo.picHeight);
281                break;
282
283            case H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY:
284                /* Picture is ready and more data remains in input buffer
285                 * -> update H264SwDecDecode() input structure, number of bytes
286                 * "consumed" is computed as difference between the new stream
287                 * pointer and old stream pointer */
288                decInput.dataLen -=
289                    (u32)(decOutput.pStrmCurrPos - decInput.pStream);
290                decInput.pStream = decOutput.pStrmCurrPos;
291                /* fall through */
292
293            case H264SWDEC_PIC_RDY:
294
295                /*lint -esym(644,tmpImage,picSize) variable initialized at
296                 * H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY case */
297
298                if (ret == H264SWDEC_PIC_RDY)
299                    decInput.dataLen = NextPacket(&decInput.pStream);
300
301                /* If enough pictures decoded -> force decoding to end
302                 * by setting that no more stream is available */
303                if (maxNumPics && picDecodeNumber == maxNumPics)
304                    decInput.dataLen = 0;
305
306                /* Increment decoding number for every decoded picture */
307                picDecodeNumber++;
308
309                /* use function H264SwDecNextPicture() to obtain next picture
310                 * in display order. Function is called until no more images
311                 * are ready for display */
312                while ( H264SwDecNextPicture(decInst, &decPicture, 0) ==
313                        H264SWDEC_PIC_RDY )
314                {
315                    DEBUG(("PIC %d, type %s", picDisplayNumber,
316                        decPicture.isIdrPicture ? "IDR" : "NON-IDR"));
317                    if (picDisplayNumber != decPicture.picId)
318                        DEBUG((", decoded pic %d", decPicture.picId));
319                    if (decPicture.nbrOfErrMBs)
320                    {
321                        DEBUG((", concealed %d\n", decPicture.nbrOfErrMBs));
322                    }
323                    else
324                        DEBUG(("\n"));
325                    fflush(stdout);
326
327                    numErrors += decPicture.nbrOfErrMBs;
328
329                    /* Increment display number for every displayed picture */
330                    picDisplayNumber++;
331
332                    /*lint -esym(644,decInfo) always initialized if pictures
333                     * available for display */
334
335                    /* Write output picture to file */
336                    imageData = (u8*)decPicture.pOutputPicture;
337                    if (cropDisplay && decInfo.croppingFlag)
338                    {
339                        tmp = CropPicture(tmpImage, imageData,
340                            decInfo.picWidth, decInfo.picHeight,
341                            &decInfo.cropParams);
342                        if (tmp)
343                            return -1;
344                        WriteOutput(outFileName, tmpImage, picSize);
345                    }
346                    else
347                    {
348                        WriteOutput(outFileName, imageData, picSize);
349                    }
350                }
351
352                break;
353
354            case H264SWDEC_STRM_PROCESSED:
355            case H264SWDEC_STRM_ERR:
356                /* Input stream was decoded but no picture is ready
357                 * -> Get more data */
358                decInput.dataLen = NextPacket(&decInput.pStream);
359                break;
360
361            default:
362                DEBUG(("FATAL ERROR\n"));
363                return -1;
364
365        }
366    /* keep decoding until all data from input stream buffer consumed */
367    } while (decInput.dataLen > 0);
368
369    /* if output in display order is preferred, the decoder shall be forced
370     * to output pictures remaining in decoded picture buffer. Use function
371     * H264SwDecNextPicture() to obtain next picture in display order. Function
372     * is called until no more images are ready for display. Second parameter
373     * for the function is set to '1' to indicate that this is end of the
374     * stream and all pictures shall be output */
375    while (H264SwDecNextPicture(decInst, &decPicture, 1) == H264SWDEC_PIC_RDY)
376    {
377        DEBUG(("PIC %d, type %s", picDisplayNumber,
378            decPicture.isIdrPicture ? "IDR" : "NON-IDR"));
379        if (picDisplayNumber != decPicture.picId)
380            DEBUG((", decoded pic %d", decPicture.picId));
381        if (decPicture.nbrOfErrMBs)
382        {
383            DEBUG((", concealed %d\n", decPicture.nbrOfErrMBs));
384        }
385        else
386            DEBUG(("\n"));
387        fflush(stdout);
388
389        numErrors += decPicture.nbrOfErrMBs;
390
391        /* Increment display number for every displayed picture */
392        picDisplayNumber++;
393
394        /* Write output picture to file */
395        imageData = (u8*)decPicture.pOutputPicture;
396        if (cropDisplay && decInfo.croppingFlag)
397        {
398            tmp = CropPicture(tmpImage, imageData,
399                decInfo.picWidth, decInfo.picHeight,
400                &decInfo.cropParams);
401            if (tmp)
402                return -1;
403            WriteOutput(outFileName, tmpImage, picSize);
404        }
405        else
406        {
407            WriteOutput(outFileName, imageData, picSize);
408        }
409    }
410
411    /* release decoder instance */
412    H264SwDecRelease(decInst);
413
414    if (foutput)
415        fclose(foutput);
416
417    /* free allocated buffers */
418    free(byteStrmStart);
419    free(tmpImage);
420
421    DEBUG(("Output file: %s\n", outFileName));
422
423    DEBUG(("DECODING DONE\n"));
424    if (numErrors || picDecodeNumber == 1)
425    {
426        DEBUG(("ERRORS FOUND\n"));
427        return 1;
428    }
429
430    return 0;
431}
432
433/*------------------------------------------------------------------------------
434
435    Function name:  WriteOutput
436
437    Purpose:
438        Write picture pointed by data to file. Size of the
439        picture in pixels is indicated by picSize.
440
441------------------------------------------------------------------------------*/
442void WriteOutput(char *filename, u8 *data, u32 picSize)
443{
444
445    /* foutput is global file pointer */
446    if (foutput == NULL)
447    {
448        /* open output file for writing, can be disabled with define.
449         * If file open fails -> exit */
450        if (strcmp(filename, "none") != 0)
451        {
452#if !defined(_NO_OUT)
453            foutput = fopen(filename, "wb");
454            if (foutput == NULL)
455            {
456                DEBUG(("UNABLE TO OPEN OUTPUT FILE\n"));
457                exit(100);
458            }
459#endif
460        }
461    }
462
463    if (foutput && data)
464        fwrite(data, 1, picSize, foutput);
465}
466
467/*------------------------------------------------------------------------------
468
469    Function name: NextPacket
470
471    Purpose:
472        Get the pointer to start of next packet in input stream. Uses
473        global variables 'packetize' and 'nalUnitStream' to determine the
474        decoder input stream mode and 'streamStop' to determine the end
475        of stream. There are three possible stream modes:
476            default - the whole stream at once
477            packetize - a single NAL-unit with start code prefix
478            nalUnitStream - a single NAL-unit without start code prefix
479
480        pStrm stores pointer to the start of previous decoder input and is
481        replaced with pointer to the start of the next decoder input.
482
483        Returns the packet size in bytes
484
485------------------------------------------------------------------------------*/
486u32 NextPacket(u8 **pStrm)
487{
488
489    u32 index;
490    u32 maxIndex;
491    u32 zeroCount;
492    u8 *stream;
493    u8 byte;
494    static u32 prevIndex=0;
495
496    /* For default stream mode all the stream is in first packet */
497    if (!packetize && !nalUnitStream)
498        return 0;
499
500    index = 0;
501    stream = *pStrm + prevIndex;
502    maxIndex = (u32)(streamStop - stream);
503
504    if (maxIndex == 0)
505        return(0);
506
507    /* leading zeros of first NAL unit */
508    do
509    {
510        byte = stream[index++];
511    } while (byte != 1 && index < maxIndex);
512
513    /* invalid start code prefix */
514    if (index == maxIndex || index < 3)
515    {
516        DEBUG(("INVALID BYTE STREAM\n"));
517        exit(100);
518    }
519
520    /* nalUnitStream is without start code prefix */
521    if (nalUnitStream)
522    {
523        stream += index;
524        maxIndex -= index;
525        index = 0;
526    }
527
528    zeroCount = 0;
529
530    /* Search stream for next start code prefix */
531    /*lint -e(716) while(1) used consciously */
532    while (1)
533    {
534        byte = stream[index++];
535        if (!byte)
536            zeroCount++;
537
538        if ( (byte == 0x01) && (zeroCount >= 2) )
539        {
540            /* Start code prefix has two zeros
541             * Third zero is assumed to be leading zero of next packet
542             * Fourth and more zeros are assumed to be trailing zeros of this
543             * packet */
544            if (zeroCount > 3)
545            {
546                index -= 4;
547                zeroCount -= 3;
548            }
549            else
550            {
551                index -= zeroCount+1;
552                zeroCount = 0;
553            }
554            break;
555        }
556        else if (byte)
557            zeroCount = 0;
558
559        if (index == maxIndex)
560        {
561            break;
562        }
563
564    }
565
566    /* Store pointer to the beginning of the packet */
567    *pStrm = stream;
568    prevIndex = index;
569
570    /* nalUnitStream is without trailing zeros */
571    if (nalUnitStream)
572        index -= zeroCount;
573
574    return(index);
575
576}
577
578/*------------------------------------------------------------------------------
579
580    Function name: CropPicture
581
582    Purpose:
583        Perform cropping for picture. Input picture pInImage with dimensions
584        picWidth x picHeight is cropped with pCropParams and the resulting
585        picture is stored in pOutImage.
586
587------------------------------------------------------------------------------*/
588u32 CropPicture(u8 *pOutImage, u8 *pInImage,
589    u32 picWidth, u32 picHeight, CropParams *pCropParams)
590{
591
592    u32 i, j;
593    u32 outWidth, outHeight;
594    u8 *pOut, *pIn;
595
596    if (pOutImage == NULL || pInImage == NULL || pCropParams == NULL ||
597        !picWidth || !picHeight)
598    {
599        /* just to prevent lint warning, returning non-zero will result in
600         * return without freeing the memory */
601        free(pOutImage);
602        return(1);
603    }
604
605    if ( ((pCropParams->cropLeftOffset + pCropParams->cropOutWidth) >
606           picWidth ) ||
607         ((pCropParams->cropTopOffset + pCropParams->cropOutHeight) >
608           picHeight ) )
609    {
610        /* just to prevent lint warning, returning non-zero will result in
611         * return without freeing the memory */
612        free(pOutImage);
613        return(1);
614    }
615
616    outWidth = pCropParams->cropOutWidth;
617    outHeight = pCropParams->cropOutHeight;
618
619    /* Calculate starting pointer for luma */
620    pIn = pInImage + pCropParams->cropTopOffset*picWidth +
621        pCropParams->cropLeftOffset;
622    pOut = pOutImage;
623
624    /* Copy luma pixel values */
625    for (i = outHeight; i; i--)
626    {
627        for (j = outWidth; j; j--)
628        {
629            *pOut++ = *pIn++;
630        }
631        pIn += picWidth - outWidth;
632    }
633
634    outWidth >>= 1;
635    outHeight >>= 1;
636
637    /* Calculate starting pointer for cb */
638    pIn = pInImage + picWidth*picHeight +
639        pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2;
640
641    /* Copy cb pixel values */
642    for (i = outHeight; i; i--)
643    {
644        for (j = outWidth; j; j--)
645        {
646            *pOut++ = *pIn++;
647        }
648        pIn += picWidth/2 - outWidth;
649    }
650
651    /* Calculate starting pointer for cr */
652    pIn = pInImage + 5*picWidth*picHeight/4 +
653        pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2;
654
655    /* Copy cr pixel values */
656    for (i = outHeight; i; i--)
657    {
658        for (j = outWidth; j; j--)
659        {
660            *pOut++ = *pIn++;
661        }
662        pIn += picWidth/2 - outWidth;
663    }
664
665    return (0);
666}
667
668/*------------------------------------------------------------------------------
669
670    Function name:  H264SwDecTrace
671
672    Purpose:
673        Example implementation of H264SwDecTrace function. Prototype of this
674        function is given in H264SwDecApi.h. This implementation appends
675        trace messages to file named 'dec_api.trc'.
676
677------------------------------------------------------------------------------*/
678void H264SwDecTrace(char *string)
679{
680    FILE *fp;
681
682    fp = fopen("dec_api.trc", "at");
683
684    if (!fp)
685        return;
686
687    fwrite(string, 1, strlen(string), fp);
688    fwrite("\n", 1,1, fp);
689
690    fclose(fp);
691}
692
693/*------------------------------------------------------------------------------
694
695    Function name:  H264SwDecMalloc
696
697    Purpose:
698        Example implementation of H264SwDecMalloc function. Prototype of this
699        function is given in H264SwDecApi.h. This implementation uses
700        library function malloc for allocation of memory.
701
702------------------------------------------------------------------------------*/
703void* H264SwDecMalloc(u32 size, u32 num)
704{
705    if (size > UINT32_MAX / num) {
706        return NULL;
707    }
708
709#if defined(CHECK_MEMORY_USAGE)
710    /* Note that if the decoder has to free and reallocate some of the buffers
711     * the total value will be invalid */
712    static u32 numBytes = 0;
713    numBytes += size * num;
714    DEBUG(("Allocated %d bytes, total %d\n", size, numBytes));
715#endif
716
717    return malloc(size * num);
718}
719
720/*------------------------------------------------------------------------------
721
722    Function name:  H264SwDecFree
723
724    Purpose:
725        Example implementation of H264SwDecFree function. Prototype of this
726        function is given in H264SwDecApi.h. This implementation uses
727        library function free for freeing of memory.
728
729------------------------------------------------------------------------------*/
730void H264SwDecFree(void *ptr)
731{
732    free(ptr);
733}
734
735/*------------------------------------------------------------------------------
736
737    Function name:  H264SwDecMemcpy
738
739    Purpose:
740        Example implementation of H264SwDecMemcpy function. Prototype of this
741        function is given in H264SwDecApi.h. This implementation uses
742        library function memcpy to copy src to dest.
743
744------------------------------------------------------------------------------*/
745void H264SwDecMemcpy(void *dest, void *src, u32 count)
746{
747    memcpy(dest, src, count);
748}
749
750/*------------------------------------------------------------------------------
751
752    Function name:  H264SwDecMemset
753
754    Purpose:
755        Example implementation of H264SwDecMemset function. Prototype of this
756        function is given in H264SwDecApi.h. This implementation uses
757        library function memset to set content of memory area pointed by ptr.
758
759------------------------------------------------------------------------------*/
760void H264SwDecMemset(void *ptr, i32 value, u32 count)
761{
762    memset(ptr, value, count);
763}
764
765