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/* CVS tag name for identification */
18const char tagName[256] = "$Name: FIRST_ANDROID_COPYRIGHT $";
19
20#include "H264SwDecApi.h"
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#define DEBUG(argv) printf argv
26
27/* _NO_OUT disables output file writing */
28#ifdef __arm
29#define _NO_OUT
30#endif
31
32/*------------------------------------------------------------------------------
33
34------------------------------------------------------------------------------*/
35void WriteOutput(FILE *fid, u8 *data, u32 picSize);
36
37u32 CropPicture(u8 *pOutImage, u8 *pInImage,
38    u32 picWidth, u32 picHeight, CropParams *pCropParams);
39
40void CropWriteOutput(FILE *fid, u8 *imageData, u32 cropDisplay,
41        H264SwDecInfo *decInfo);
42
43typedef struct
44{
45    H264SwDecInst decInst;
46    H264SwDecInput decInput;
47    H264SwDecOutput decOutput;
48    H264SwDecPicture decPicture;
49    H264SwDecInfo decInfo;
50    FILE *foutput;
51    char outFileName[256];
52    u8 *byteStrmStart;
53    u32 picNumber;
54} Decoder;
55
56
57/*------------------------------------------------------------------------------
58
59------------------------------------------------------------------------------*/
60int main(int argc, char **argv)
61{
62
63    i32 instCount, instRunning;
64    i32 i;
65    u32 maxNumPics;
66    u32 strmLen;
67    H264SwDecRet ret;
68    u32 numErrors = 0;
69    u32 cropDisplay = 0;
70    u32 disableOutputReordering = 0;
71    FILE *finput;
72    Decoder **decoder;
73    char outFileName[256] = "out.yuv";
74
75
76    if ( argc > 1 && strcmp(argv[1], "-T") == 0 )
77    {
78        fprintf(stderr, "%s\n", tagName);
79        return 0;
80    }
81
82    if (argc < 2)
83    {
84        DEBUG((
85            "Usage: %s [-Nn] [-Ooutfile] [-P] [-U] [-C] [-R] [-T] file1.264 [file2.264] .. [fileN.264]\n",
86            argv[0]));
87        DEBUG(("\t-Nn forces decoding to stop after n pictures\n"));
88#if defined(_NO_OUT)
89        DEBUG(("\t-Ooutfile output writing disabled at compile time\n"));
90#else
91        DEBUG(("\t-Ooutfile write output to \"outfile\" (default out.yuv)\n"));
92        DEBUG(("\t-Onone does not write output\n"));
93#endif
94        DEBUG(("\t-C display cropped image (default decoded image)\n"));
95        DEBUG(("\t-R disable DPB output reordering\n"));
96        DEBUG(("\t-T to print tag name and exit\n"));
97        exit(100);
98    }
99
100    instCount = argc - 1;
101
102    /* read command line arguments */
103    maxNumPics = 0;
104    for (i = 1; i < (argc-1); i++)
105    {
106        if ( strncmp(argv[i], "-N", 2) == 0 )
107        {
108            maxNumPics = (u32)atoi(argv[i]+2);
109            instCount--;
110        }
111        else if ( strncmp(argv[i], "-O", 2) == 0 )
112        {
113            strcpy(outFileName, argv[i]+2);
114            instCount--;
115        }
116        else if ( strcmp(argv[i], "-C") == 0 )
117        {
118            cropDisplay = 1;
119            instCount--;
120        }
121        else if ( strcmp(argv[i], "-R") == 0 )
122        {
123            disableOutputReordering = 1;
124            instCount--;
125        }
126    }
127
128    if (instCount < 1)
129    {
130        DEBUG(("No input files\n"));
131        exit(100);
132    }
133
134    /* allocate memory for multiple decoder instances
135     * one instance for every stream file */
136    decoder = (Decoder **)malloc(sizeof(Decoder*)*(u32)instCount);
137    if (decoder == NULL)
138    {
139        DEBUG(("Unable to allocate memory\n"));
140        exit(100);
141    }
142
143    /* prepare each decoder instance */
144    for (i = 0; i < instCount; i++)
145    {
146        decoder[i] = (Decoder *)calloc(1, sizeof(Decoder));
147
148        /* open input file */
149        finput = fopen(argv[argc-instCount+i],"rb");
150        if (finput == NULL)
151        {
152            DEBUG(("Unable to open input file <%s>\n", argv[argc-instCount+i]));
153            exit(100);
154        }
155
156        DEBUG(("Reading input file[%d] %s\n", i, argv[argc-instCount+i]));
157
158        /* read input stream to buffer */
159        fseek(finput,0L,SEEK_END);
160        strmLen = (u32)ftell(finput);
161        rewind(finput);
162        decoder[i]->byteStrmStart = (u8 *)malloc(sizeof(u8)*strmLen);
163        if (decoder[i]->byteStrmStart == NULL)
164        {
165            DEBUG(("Unable to allocate memory\n"));
166            exit(100);
167        }
168        fread(decoder[i]->byteStrmStart, sizeof(u8), strmLen, finput);
169        fclose(finput);
170
171        /* open output file */
172        if (strcmp(outFileName, "none") != 0)
173        {
174#if defined(_NO_OUT)
175            decoder[i]->foutput = NULL;
176#else
177            sprintf(decoder[i]->outFileName, "%s%i", outFileName, i);
178            decoder[i]->foutput = fopen(decoder[i]->outFileName, "wb");
179            if (decoder[i]->foutput == NULL)
180            {
181                DEBUG(("Unable to open output file\n"));
182                exit(100);
183            }
184#endif
185        }
186
187        ret = H264SwDecInit(&(decoder[i]->decInst), disableOutputReordering);
188
189        if (ret != H264SWDEC_OK)
190        {
191            DEBUG(("Init failed %d\n", ret));
192            exit(100);
193        }
194
195        decoder[i]->decInput.pStream = decoder[i]->byteStrmStart;
196        decoder[i]->decInput.dataLen = strmLen;
197        decoder[i]->decInput.intraConcealmentMethod = 0;
198
199    }
200
201    /* main decoding loop */
202    do
203    {
204        /* decode once using each instance */
205        for (i = 0; i < instCount; i++)
206        {
207            ret = H264SwDecDecode(decoder[i]->decInst,
208                                &(decoder[i]->decInput),
209                                &(decoder[i]->decOutput));
210
211            switch(ret)
212            {
213
214                case H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY:
215
216                    ret = H264SwDecGetInfo(decoder[i]->decInst,
217                            &(decoder[i]->decInfo));
218                    if (ret != H264SWDEC_OK)
219                        exit(1);
220
221                    if (cropDisplay && decoder[i]->decInfo.croppingFlag)
222                    {
223                        DEBUG(("Decoder[%d] Cropping params: (%d, %d) %dx%d\n",
224                            i,
225                            decoder[i]->decInfo.cropParams.cropLeftOffset,
226                            decoder[i]->decInfo.cropParams.cropTopOffset,
227                            decoder[i]->decInfo.cropParams.cropOutWidth,
228                            decoder[i]->decInfo.cropParams.cropOutHeight));
229                    }
230
231                    DEBUG(("Decoder[%d] Width %d Height %d\n", i,
232                        decoder[i]->decInfo.picWidth,
233                        decoder[i]->decInfo.picHeight));
234
235                    DEBUG(("Decoder[%d] videoRange %d, matricCoefficients %d\n",
236                        i, decoder[i]->decInfo.videoRange,
237                        decoder[i]->decInfo.matrixCoefficients));
238                    decoder[i]->decInput.dataLen -=
239                        (u32)(decoder[i]->decOutput.pStrmCurrPos -
240                              decoder[i]->decInput.pStream);
241                    decoder[i]->decInput.pStream =
242                        decoder[i]->decOutput.pStrmCurrPos;
243                    break;
244
245                case H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY:
246                    decoder[i]->decInput.dataLen -=
247                        (u32)(decoder[i]->decOutput.pStrmCurrPos -
248                              decoder[i]->decInput.pStream);
249                    decoder[i]->decInput.pStream =
250                        decoder[i]->decOutput.pStrmCurrPos;
251                    /* fall through */
252                case H264SWDEC_PIC_RDY:
253                    if (ret == H264SWDEC_PIC_RDY)
254                        decoder[i]->decInput.dataLen = 0;
255
256                    ret = H264SwDecGetInfo(decoder[i]->decInst,
257                            &(decoder[i]->decInfo));
258                    if (ret != H264SWDEC_OK)
259                        exit(1);
260
261                    while (H264SwDecNextPicture(decoder[i]->decInst,
262                            &(decoder[i]->decPicture), 0) == H264SWDEC_PIC_RDY)
263                    {
264                        decoder[i]->picNumber++;
265
266                        numErrors += decoder[i]->decPicture.nbrOfErrMBs;
267
268                        DEBUG(("Decoder[%d] PIC %d, type %s, concealed %d\n",
269                            i, decoder[i]->picNumber,
270                            decoder[i]->decPicture.isIdrPicture
271                                ? "IDR" : "NON-IDR",
272                            decoder[i]->decPicture.nbrOfErrMBs));
273                        fflush(stdout);
274
275                        CropWriteOutput(decoder[i]->foutput,
276                                (u8*)decoder[i]->decPicture.pOutputPicture,
277                                cropDisplay, &(decoder[i]->decInfo));
278                    }
279
280                    if (maxNumPics && decoder[i]->picNumber == maxNumPics)
281                        decoder[i]->decInput.dataLen = 0;
282                    break;
283
284                case H264SWDEC_STRM_PROCESSED:
285                case H264SWDEC_STRM_ERR:
286                case H264SWDEC_PARAM_ERR:
287                    decoder[i]->decInput.dataLen = 0;
288                    break;
289
290                default:
291                    DEBUG(("Decoder[%d] FATAL ERROR\n", i));
292                    exit(10);
293                    break;
294
295            }
296        }
297
298        /* check if any of the instances is still running (=has more data) */
299        instRunning = instCount;
300        for (i = 0; i < instCount; i++)
301        {
302            if (decoder[i]->decInput.dataLen == 0)
303                instRunning--;
304        }
305
306    } while (instRunning);
307
308
309    /* get last frames and close each instance */
310    for (i = 0; i < instCount; i++)
311    {
312        while (H264SwDecNextPicture(decoder[i]->decInst,
313                &(decoder[i]->decPicture), 1) == H264SWDEC_PIC_RDY)
314        {
315            decoder[i]->picNumber++;
316
317            DEBUG(("Decoder[%d] PIC %d, type %s, concealed %d\n",
318                i, decoder[i]->picNumber,
319                decoder[i]->decPicture.isIdrPicture
320                    ? "IDR" : "NON-IDR",
321                decoder[i]->decPicture.nbrOfErrMBs));
322            fflush(stdout);
323
324            CropWriteOutput(decoder[i]->foutput,
325                    (u8*)decoder[i]->decPicture.pOutputPicture,
326                    cropDisplay, &(decoder[i]->decInfo));
327        }
328
329        H264SwDecRelease(decoder[i]->decInst);
330
331        if (decoder[i]->foutput)
332            fclose(decoder[i]->foutput);
333
334        free(decoder[i]->byteStrmStart);
335
336        free(decoder[i]);
337    }
338
339    free(decoder);
340
341    if (numErrors)
342        return 1;
343    else
344        return 0;
345
346}
347
348/*------------------------------------------------------------------------------
349
350------------------------------------------------------------------------------*/
351void CropWriteOutput(FILE *foutput, u8 *imageData, u32 cropDisplay,
352        H264SwDecInfo *decInfo)
353{
354    u8 *tmpImage = NULL;
355    u32 tmp, picSize;
356
357    if (cropDisplay && decInfo->croppingFlag)
358    {
359        picSize = decInfo->cropParams.cropOutWidth *
360                  decInfo->cropParams.cropOutHeight;
361        picSize = (3 * picSize)/2;
362        tmpImage = malloc(picSize);
363        if (tmpImage == NULL)
364            exit(1);
365        tmp = CropPicture(tmpImage, imageData,
366            decInfo->picWidth, decInfo->picHeight,
367            &(decInfo->cropParams));
368        if (tmp)
369            exit(1);
370        WriteOutput(foutput, tmpImage, picSize);
371        free(tmpImage);
372    }
373    else
374    {
375        picSize = decInfo->picWidth * decInfo->picHeight;
376        picSize = (3 * picSize)/2;
377        WriteOutput(foutput, imageData, picSize);
378    }
379
380}
381
382/*------------------------------------------------------------------------------
383
384------------------------------------------------------------------------------*/
385void WriteOutput(FILE *fid, u8 *data, u32 picSize)
386{
387    if (fid)
388        fwrite(data, 1, picSize, fid);
389}
390
391/*------------------------------------------------------------------------------
392
393    Function name:  H264SwDecTrace
394
395------------------------------------------------------------------------------*/
396void H264SwDecTrace(char *string)
397{
398    FILE *fp;
399
400    fp = fopen("dec_api.trc", "at");
401
402    if (!fp)
403        return;
404
405    fwrite(string, 1, strlen(string), fp);
406    fwrite("\n", 1,1, fp);
407
408    fclose(fp);
409}
410
411/*------------------------------------------------------------------------------
412
413    Function name:  H264SwDecmalloc
414
415------------------------------------------------------------------------------*/
416void* H264SwDecMalloc(u32 size)
417{
418    return malloc(size);
419}
420
421/*------------------------------------------------------------------------------
422
423    Function name:  H264SwDecFree
424
425------------------------------------------------------------------------------*/
426void H264SwDecFree(void *ptr)
427{
428    free(ptr);
429}
430
431/*------------------------------------------------------------------------------
432
433    Function name:  H264SwDecMemcpy
434
435------------------------------------------------------------------------------*/
436void H264SwDecMemcpy(void *dest, void *src, u32 count)
437{
438    memcpy(dest, src, count);
439}
440
441/*------------------------------------------------------------------------------
442
443    Function name:  H264SwDecMemset
444
445------------------------------------------------------------------------------*/
446void H264SwDecMemset(void *ptr, i32 value, u32 count)
447{
448    memset(ptr, value, count);
449}
450
451/*------------------------------------------------------------------------------
452
453    Function name: CropPicture
454
455------------------------------------------------------------------------------*/
456u32 CropPicture(u8 *pOutImage, u8 *pInImage,
457    u32 picWidth, u32 picHeight, CropParams *pCropParams)
458{
459
460    u32 i, j;
461    u32 outWidth, outHeight;
462    u8 *pOut, *pIn;
463
464    if (pOutImage == NULL || pInImage == NULL || pCropParams == NULL ||
465        !picWidth || !picHeight)
466    {
467        /* due to lint warning */
468        free(pOutImage);
469        return(1);
470    }
471
472    if ( ((pCropParams->cropLeftOffset + pCropParams->cropOutWidth) >
473           picWidth ) ||
474         ((pCropParams->cropTopOffset + pCropParams->cropOutHeight) >
475           picHeight ) )
476    {
477        /* due to lint warning */
478        free(pOutImage);
479        return(1);
480    }
481
482    outWidth = pCropParams->cropOutWidth;
483    outHeight = pCropParams->cropOutHeight;
484
485    pIn = pInImage + pCropParams->cropTopOffset*picWidth +
486        pCropParams->cropLeftOffset;
487    pOut = pOutImage;
488
489    /* luma */
490    for (i = outHeight; i; i--)
491    {
492        for (j = outWidth; j; j--)
493        {
494            *pOut++ = *pIn++;
495        }
496        pIn += picWidth - outWidth;
497    }
498
499    outWidth >>= 1;
500    outHeight >>= 1;
501
502    pIn = pInImage + picWidth*picHeight +
503        pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2;
504
505    /* cb */
506    for (i = outHeight; i; i--)
507    {
508        for (j = outWidth; j; j--)
509        {
510            *pOut++ = *pIn++;
511        }
512        pIn += picWidth/2 - outWidth;
513    }
514
515    pIn = pInImage + 5*picWidth*picHeight/4 +
516        pCropParams->cropTopOffset*picWidth/4 + pCropParams->cropLeftOffset/2;
517
518    /* cr */
519    for (i = outHeight; i; i--)
520    {
521        for (j = outWidth; j; j--)
522        {
523            *pOut++ = *pIn++;
524        }
525        pIn += picWidth/2 - outWidth;
526    }
527
528    return (0);
529
530}
531
532